repctl 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in repctl.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Repctl - Manage Replication among a set of SQL Servers
2
+
3
+ `repctl` is a utility to configure, reconfigure, start, stop, crash, generate
4
+ workloads, dump, restore, benchmark, and monitor a set of SQL servers for
5
+ development environments. Replication relationships can be set up among server
6
+ instances with a single command. While running a load generator or benchmark,
7
+ the replication status, including current lag, can be seen in a continuously
8
+ updated display. A slave can be added to an existing server that already has
9
+ data.
10
+
11
+ The `repctl` gem includes a _Thor_ script that makes all the `repctl`
12
+ functionality available at the command line.
13
+
14
+ ## Limitations
15
+
16
+ Currently only MySQL is supported but PostgresSQL will soon be added. All the
17
+ server instances must run on a single host. This restriction may be soon lifted
18
+ as well.
19
+
20
+ ## Installation
21
+
22
+ You will need to have a local installation installation of MySQL. You do not
23
+ need to do anything to configure the installation. For example, if you compile
24
+ MySQL from source, then do `make install`, then you are done! No MySQL
25
+ post-installation steps are necessary. All post-install configuration is
26
+ handled by `repctl`.
27
+
28
+ The top
29
+
30
+ == Available Commands
31
+
32
+ tethys:repctl mbs$ thor list
33
+ mysql
34
+ -----
35
+ thor mysql:change_master MASTER SLAVE FILE POSITION # Execute CHANGE MASTER TO on the SLAVE.
36
+ thor mysql:cluster_user INSTANCE # Create the cluster user account on a MySQL instance.
37
+ thor mysql:config INSTANCE # Initialize the data directory for a new instance.
38
+ thor mysql:config_all # Initialize the data directories for all instances.
39
+ thor mysql:crash INSTANCE # Crash a running MySQL server.
40
+ thor mysql:dump INSTANCE [DUMPFILE] # Dump all databases after FLUSH TABLES WITH READ LOCK
41
+ thor mysql:repl_user INSTANCE # Create the replication user account on a MySQL insta...
42
+ thor mysql:reset INSTANCE # Remove database and restart MySQL server.
43
+ thor mysql:reset_all # Remove all databases and restart MySQL instances.
44
+ thor mysql:restore INSTANCE [DUMPFILE] # Restore INSTANCE from a 'mysqldump' file DUMPFILE.
45
+ thor mysql:start_slave SLAVE # Issue START SLAVE on the SLAVE MySQL instance.
46
+ thor mysql:status # Show the status of replication.
47
+ thor mysql:stop INSTANCE # Stop a running MySQL server instance.
48
+ thor mysql:stop_all # Stop all the MySQL servers.
49
+
50
+ setup
51
+ -----
52
+ thor setup:add_slave MASTER SLAVE # Master has some data that is used to initialize the slave.
53
+ thor setup:repl_pair MASTER SLAVE # Set up a single master/slave replication pair from the very beginning.
54
+
55
+ utils
56
+ -----
57
+ thor utils:bench [INSTANCE] [PROPS] # Run the Tungsten Bristlecone benchmarker. The INSTAN...
58
+ thor utils:create_db [INSTANCE] [DBNAME] # "Create a database on a MySQL instance. INSTANCE de...
59
+ thor utils:create_tbl [INSTANCE] [DBNAME] [TBLNAME] # Create a database table. INSTANCE defaults to DEFAU...
60
+ thor utils:gen_rows [INSTANCE], [DBNAME], [TBLNAME] # Add rows to a table that was created by "utils:crea...
61
+
62
+ == Configuring Simple Repctl
63
+
64
+ This tool needs some configuration before you can use it.
65
+
66
+ You should have an valid MySQL installation and the Thor gem installed. Your existing MySQL server will not be affected by the +repctl+ script. However, binaries from this installation will be reused. In the +config.rb+ file set the constants:
67
+
68
+ * MYSQL_HOME -- the location of the local MySQL installation
69
+ * DATA_HOME -- the location of the directory where per-MySQL server data directories are created.
70
+ * DUMP_DIR -- the location where you want dump files to be stored
71
+ * RELAY_LOG -- adjust this according to your hostname
72
+
73
+ Next, define the potential instances you want to create. Edit the <tt>servers.yml</tt> file as appropriate.
74
+
75
+ Finally, edit the existing <tt>my*.cnf*</tt> files to at least have the correct <tt>datadir</tt> defined.
76
+
77
+ == Using Simple Repctl
78
+
79
+ You are now ready to rock. Run <tt>thor mysql:start_all</tt> to start up all the servers listed in your +servers.yml+ file. Instead or subsequently, you can run <tt>thor setup:repl_pair 1 2</tt> to reset everything and create a master/slave replication pair. Start up some load to the MySQL master (at socket +/tmp/mysql1.sock+, by default), then watch the replication status change by running <tt>thor mysql:status -s 1 2 -c 5</tt> to see a continuous update of the status, updated every 5 seconds. Add a new slave using instance +3+, which may or may not be running and may or may not have its data directory initialized, by running <tt>thor setup:add_slave 1 3</tt>. This does a dump on the master and a restore on the slave and restarts replication using the proper replication coordinates.
80
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/mysql.thor ADDED
@@ -0,0 +1,431 @@
1
+ require 'socket'
2
+ require 'repctl'
3
+
4
+ # Thor has the 'helpful' property that any Thor task gets executed only
5
+ # once. The 'Helpers' module makes many Thor tasks available as ordinary
6
+ # Ruby functions for internal use. The corresponding Thor tasks usually
7
+ # delegate to the corresponding helper function with 'super'.
8
+ module Helpers
9
+
10
+ include Repctl::Config
11
+ include Repctl::Servers
12
+
13
+ def start(instance)
14
+ say "Starting instance #{instance}.", :green
15
+ do_start(instance)
16
+ end
17
+
18
+ def start_all
19
+ all_instances.each do |instance|
20
+ start(instance)
21
+ end
22
+ end
23
+
24
+ def stop(instance)
25
+ say "Stopping instance #{instance}.", :green
26
+ do_admin(instance, "shutdown")
27
+ end
28
+
29
+ def stop_all
30
+ all_live_instances.each do |instance|
31
+ stop(instance)
32
+ end
33
+ end
34
+
35
+ def config(instance)
36
+ say "Initializing new data directory for instance #{instance}."
37
+ do_config(instance)
38
+ end
39
+
40
+ def config_all
41
+ all_instances.each do |instance|
42
+ config(instance)
43
+ end
44
+ end
45
+
46
+ def secure_accounts(instance)
47
+ do_secure_accounts(instance)
48
+ end
49
+
50
+ def secure_accounts_all
51
+ Repctl::Servers.all_live_instances.each do |instance|
52
+ secure_accounts(instance)
53
+ end
54
+ end
55
+
56
+ def reset(instance)
57
+ stop(instance)
58
+ config(instance)
59
+ start(instance)
60
+ secure_accounts(instance)
61
+ end
62
+
63
+ def restart(instance)
64
+ stop(instance)
65
+ start(instance)
66
+ end
67
+
68
+ def reset_all
69
+ all_instances.each do |instance|
70
+ reset(instance)
71
+ end
72
+ end
73
+
74
+ def change_master(master, slave, file, position)
75
+ say "Changing master: master = #{master}, slave = #{slave}, file = #{file}, position = #{position}"
76
+ do_change_master(master, slave, :file => file, :position => position)
77
+ end
78
+
79
+ def start_slave(slave)
80
+ say "Starting slave #{slave}", :green
81
+ run_mysql_query(slave, "START SLAVE")
82
+ end
83
+
84
+ def crash(instance)
85
+ say "Crashing instance #{instance}", :red
86
+ do_crash(instance)
87
+ end
88
+
89
+ def repl_user(instance)
90
+ say "Creating replication account on instance #{instance}.", :green
91
+ do_repl_user(instance)
92
+ end
93
+
94
+ def cluster_user(instance = 1)
95
+ say "Installing cluster user for instance #{instance}.", :green
96
+ do_cluster_user(instance)
97
+ end
98
+
99
+ end # Module helpers
100
+
101
+ class Mysql < Thor
102
+
103
+ include Thor::Actions
104
+ include Repctl::Config
105
+ include Repctl::Commands
106
+ include Repctl::Servers
107
+ include Helpers
108
+
109
+ desc "start INSTANCE", "Ensure that the given MySQL server instance is running."
110
+ def start(instance)
111
+ super
112
+ end
113
+
114
+ desc "start_all", "Start all the MySQL instances."
115
+ def start_all
116
+ super
117
+ end
118
+
119
+ desc "stop INSTANCE", "Stop a running MySQL server instance."
120
+ def stop(instance)
121
+ super
122
+ end
123
+
124
+ desc "stop_all", "Stop all the MySQL servers."
125
+ def stop_all
126
+ super
127
+ end
128
+
129
+ desc "config INSTANCE", "Initialize the data directory for a new instance."
130
+ def config(instance)
131
+ super
132
+ end
133
+
134
+ desc "config_all", "Initialize the data directories for all instances."
135
+ def config_all
136
+ super
137
+ end
138
+
139
+ desc "secure_accounts INSTANCE", "Add passwords for root and anonymous accounts."
140
+ def secure_accounts(instance)
141
+ super
142
+ end
143
+
144
+ desc "secure_accounts_all", "Add passwords for root and anonymous accounts for all instances."
145
+ def secure_accounts_all
146
+ super
147
+ end
148
+
149
+ desc "reset", "Remove the database data directory, reconfigure and restart the instance."
150
+ def reset(instance)
151
+ super
152
+ end
153
+
154
+ desc "reset_all", "Remove all databases and restart MySQL instances."
155
+ def reset_all
156
+ super
157
+ end
158
+
159
+ desc "start_slave SLAVE", "Issue START SLAVE on the SLAVE MySQL instance."
160
+ def start_slave(slave)
161
+ super
162
+ end
163
+
164
+ desc "change_master MASTER SLAVE FILE POSITION", "Execute CHANGE MASTER TO on the SLAVE."
165
+ def change_master(master, slave, file, position)
166
+ super
167
+ end
168
+
169
+ desc "crash INSTANCE", "Crash a running MySQL server."
170
+ def crash(instance)
171
+ super
172
+ end
173
+
174
+ desc "repl_user INSTANCE", "Create the replication user account on a MySQL instance."
175
+ def repl_user(instance)
176
+ super
177
+ end
178
+
179
+ desc "cluster_user INSTANCE", "Create the cluster user account on a MySQL instance."
180
+ def cluster_user(instance)
181
+ super
182
+ end
183
+
184
+ desc "repl_status", "Show the status of replication."
185
+ method_option :continuous, :aliases => "-c", :type => :numeric,
186
+ :desc => "Continuous output at specified interval (in seconds)."
187
+ method_option :servers, :aliases => "-s", :type => :array,
188
+ :desc => "Only check the status of given servers."
189
+ def repl_status
190
+ todos = options[:servers] || all_live_instances
191
+ unless todos.any?
192
+ say "No Running Servers.", :blue
193
+ return
194
+ end
195
+ header = sprintf("%-5s%-25s%-25s%-25s%-8s\n",
196
+ "inst", "master", "received", "applied", "lag")
197
+
198
+ loop do
199
+ say header, :blue
200
+
201
+ todos.each do |i|
202
+ coordinates = get_coordinates(i)
203
+ slave_status = get_slave_status(i)
204
+ is_slave = !(slave_status["Error"] == "MySQL server is not a slave.")
205
+ master_file = coordinates[:file]
206
+ master_pos = coordinates[:position]
207
+ if is_slave
208
+ recv_file = slave_status["Master_Log_File"]
209
+ recv_pos = slave_status["Read_Master_Log_Pos"]
210
+ apply_file = slave_status["Relay_Master_Log_File"]
211
+ apply_pos = slave_status["Exec_Master_Log_Pos"]
212
+ lag = slave_status["Seconds_Behind_Master"]
213
+ end
214
+
215
+ format = "%-5d%16s:%-8d"
216
+ if is_slave
217
+ if lag
218
+ lag = lag.to_s
219
+ else
220
+ lag = "-"
221
+ end
222
+ format += "%16s:%-8d%16s:%-8d%-8s"
223
+ str = sprintf(format, i, master_file, master_pos, recv_file, recv_pos,
224
+ apply_file, apply_pos, lag)
225
+ else
226
+ str = sprintf(format, i, master_file, master_pos)
227
+ end
228
+
229
+ say str + "\n", :yellow
230
+ end
231
+ break unless options[:continuous]
232
+ sleep options[:continuous]
233
+ say ""
234
+ end
235
+ end
236
+
237
+ desc "dump INSTANCE [DUMPFILE]", "Dump all databases after FLUSH TABLES WITH READ LOCK"
238
+ def dump(instance, dumpfile = DEFAULT_DUMPFILE)
239
+ coordinates = do_dump(instance, dumpfile)
240
+ file = coordinates[:file]
241
+ position = coordinates[:position]
242
+ puts "(#{file}, #{position})"
243
+ [file, String(position)]
244
+ end
245
+
246
+ desc "restore INSTANCE [DUMPFILE]", "Restore INSTANCE from a \'mysqldump\' file DUMPFILE."
247
+ def restore(slave, dumpfile = DEFAULT_DUMPFILE)
248
+ do_restore(slave, dumpfile)
249
+ end
250
+
251
+ end
252
+
253
+ class Utils < Thor
254
+
255
+ include Thor::Actions
256
+ include Repctl::Config
257
+ include Repctl::Commands
258
+ include Repctl::Servers
259
+ include Helpers
260
+
261
+ DEFAULT_MASTER = 1
262
+
263
+ desc "bench [INSTANCE] [PROPS]", "Run the Tungsten Bristlecone benchmarker.
264
+ The INSTANCE specifies the instance to perform all operations to, and PROPS
265
+ is the properties file to use. The INSTANCE defaults to #{DEFAULT_MASTER} and
266
+ the properties file defaults to #{BENCHMARK_PROPERTIES}."
267
+ def bench(instance = DEFAULT_MASTER, props = nil)
268
+ props ||= BENCHMARK_PROPERTIES
269
+ invoke :create_db, [instance, "widgets"]
270
+ run("#{BENCHMARK} -props #{props}", :verbose => true, :capture => false)
271
+ end
272
+
273
+ desc "create_db [INSTANCE] [DBNAME]", <<-EOS
274
+ "Create a database on a MySQL instance. INSTANCE defaults to DEFAULT_MASTER,
275
+ and DBNAME defaults to "widgets".
276
+ EOS
277
+ method_option :replace, :type => :boolean, :aliases => "-r",
278
+ :desc => "drop and recreate the database"
279
+ def create_db(instance = DEFAULT_MASTER, dbname = "widgets")
280
+ run_mysql_query(instance, "DROP DATABASE IF EXISTS #{dbname}") if options[:replace]
281
+ run_mysql_query(instance, "CREATE DATABASE IF NOT EXISTS #{dbname}")
282
+ end
283
+
284
+ desc "create_tbl [INSTANCE] [DBNAME] [TBLNAME]", <<-EOS
285
+ Create a database table. INSTANCE defaults to DEFAULT_MASTER, DBNAME defaults
286
+ to "widgets" and TBLNAME defaults to "users". The table schema is fixed.
287
+ EOS
288
+ method_option :replace, :type => :boolean, :aliases => "-r",
289
+ :desc => "drop and recreate the table"
290
+ def create_tbl(instance = DEFAULT_MASTER, dbname = "widgets", tblname = "users")
291
+ invoke :create_db, [instance, dbname], :replace => false
292
+ run_mysql_query(instance,
293
+ "DROP TABLE IF EXISTS #{dbname}.#{tblname}") if options[:replace]
294
+ cmd = <<-EOS
295
+ CREATE TABLE #{dbname}.#{tblname} (
296
+ id INT NOT NULL,
297
+ last_name CHAR(30) NOT NULL,
298
+ first_name CHAR(30) NOT NULL,
299
+ credentials VARCHAR(32768) NOT NULL,
300
+ PRIMARY KEY (id),
301
+ INDEX name (last_name,first_name)
302
+ )
303
+ EOS
304
+ run_mysql_query(instance, cmd)
305
+ end
306
+
307
+ desc "gen_rows [INSTANCE], [DBNAME], [TBLNAME]", <<-EOS
308
+ Add rows to a table that was created by "utils:create_tbl". INSTANCE defaults
309
+ to DEFAULT_MASTER, DBNAME defaults to "widgets", and TBLNAME defaults to "users".
310
+ EOS
311
+ method_option :delay, :type => :numeric, :aliases => "-d", :default => 0,
312
+ :desc => "sleep for the specified number of milliseconds between row inserts."
313
+ method_option :count, :type => :numeric, :aliases => "-c", :default => 1000,
314
+ :desc => "number of rows to insert"
315
+ method_option :size, :type => :numeric, :aliases => "-s", :default => 100,
316
+ :desc => "the approximate size of the record to insert (in bytes)."
317
+ method_option :forever, :type => :boolean, :aliases => "-f",
318
+ :desc => "run forever, ignoring COUNT option."
319
+ method_option :verbose, :type => :boolean, :aliases => "-v",
320
+ :desc => "print a '.' for each row inserted."
321
+ def gen_rows(instance = DEFAULT_MASTER, dbname = "widgets", tblname = "users")
322
+ invoke :create_tbl, [instance, dbname], :replace => true
323
+ size = options[:size]
324
+ size ||= 100
325
+ size = [size, 32768].min
326
+ data = IO.read("#{Mysql::DATA_HOME}/words.txt", size)
327
+ id = 1
328
+ count = 0
329
+
330
+ loop do
331
+ cmd = <<-EOS
332
+ INSERT INTO #{dbname}.#{tblname} VALUES (
333
+ #{id},
334
+ 'Fillmore',
335
+ 'Millard',
336
+ '#{data}'
337
+ )
338
+ EOS
339
+ run_mysql_query(instance, cmd)
340
+ putc "." if options[:verbose]
341
+ id += 1
342
+ count += 1
343
+ break if (count >= options[:count] and (not options[:forever]))
344
+ msecs = options[:delay]
345
+ sleep(msecs / 1000.0) if msecs > 0
346
+ end
347
+
348
+ end
349
+
350
+ end
351
+
352
+ class Setup < Thor
353
+
354
+ include ::Thor::Actions
355
+ include Repctl::Config
356
+ include Repctl::Commands
357
+ include Repctl::Servers
358
+ include Helpers
359
+
360
+ #
361
+ # Setting Up Replication with New Master and Slaves.
362
+ # Here, we stop all MySQL servers, remove the data directories, reinitialize
363
+ # the data directories, restart the servers, and set up a master/slave
364
+ # relationship.
365
+ #
366
+ desc "repl_pair MASTER SLAVE",
367
+ "Set up a single master/slave replication pair from the very beginning."
368
+ def repl_pair(master, slave)
369
+ say "master is #{master}, slave is #{slave}", :green
370
+ reset(master)
371
+ reset(slave)
372
+ cluster_user(master)
373
+ repl_user(master)
374
+ coordinates = get_coordinates(master)
375
+ file = coordinates[:file]
376
+ position = coordinates[:position]
377
+ say "File is #{file}, Position is #{position}", :green
378
+ change_master(master, slave, file, position)
379
+ start_slave(slave)
380
+ end
381
+
382
+ desc "repl_trio MASTER SLAVE1 SLAVE2",
383
+ "Set up a single master and two slave replication cluster."
384
+ method_option :reset, :type => :boolean, :default => true
385
+ def repl_trio(master, slave1, slave2)
386
+ say "master is #{master}, slaves are #{slave1} and #{slave2}", :green
387
+ if options[:reset]
388
+ reset(master)
389
+ reset(slave1)
390
+ reset(slave2)
391
+ cluster_user(master)
392
+ repl_user(master)
393
+ else
394
+ restart(master)
395
+ restart(slave1)
396
+ restart(slave2)
397
+ end
398
+ coordinates = get_coordinates(master)
399
+ file = coordinates[:file]
400
+ position = coordinates[:position]
401
+ say "File is #{file}, Position is #{position}", :green
402
+ change_master(master, slave1, file, position)
403
+ start_slave(slave1)
404
+ change_master(master, slave2, file, position)
405
+ start_slave(slave2)
406
+ end
407
+
408
+ #
409
+ # Setting Up Replication with Existing Data using the 'mysqldump' utility. The
410
+ # master has existing data.
411
+ #
412
+ desc "add_slave MASTER SLAVE", "Master has some data that is used to initialize the slave."
413
+ method_option :populate, :type => :boolean, :default => false
414
+ def add_slave(master, slave)
415
+ reset(slave)
416
+
417
+ if options[:populate]
418
+ invoke "utils:bench", [master, "/opt/MySQL/b2.properties"]
419
+ end
420
+ file, position = invoke "mysql:dump", [master]
421
+
422
+ # Slave is running, but it is not yet configured as a slave.
423
+ # Load slave from the dump file...
424
+ invoke "mysql:restore", [slave]
425
+
426
+ change_master(master, slave, file, position)
427
+ start_slave(slave)
428
+ end
429
+
430
+ end
431
+
@@ -0,0 +1,29 @@
1
+ url=jdbc:mysql://localhost:3307/widgets
2
+ user=cluster
3
+ password=secret
4
+ type=MySQL 5.6.2-m5
5
+ analyzeCmd=select 1
6
+
7
+ # Benchmark test to compare clustered and non-clustered write performance.
8
+ #
9
+ # We execute INSERT statements with varying numbers of clients and tables.
10
+ #
11
+ # To invoke this test try the following command.
12
+ # $benchmark.sh -props WriteSimpleScenario.properties
13
+
14
+ # Scenario name.
15
+ scenario=com.continuent.bristlecone.benchmark.scenarios.WriteSimpleScenario
16
+
17
+ # Database connection information.
18
+ # include=connection_postgresql.properties|connection_pcluster.properties
19
+
20
+ # Test duration and number of threads.
21
+ bound=duration
22
+ duration=60
23
+ threads=1|10|20
24
+
25
+ # Database table information.
26
+ tables=1|16
27
+ datatype=varchar
28
+ datawidth=100
29
+ datarows=100
data/config/config.rb ADDED
@@ -0,0 +1,50 @@
1
+ module Repctl
2
+
3
+ module Config
4
+
5
+ # The location of the local MySQL installation.
6
+ MYSQL_HOME = "/usr/local/mysql"
7
+
8
+ ROOT_PASSWORD = "har526"
9
+
10
+ SERVER_CONFIG = File.expand_path("../servers.yml", __FILE__)
11
+
12
+ # Define the directory where subdirectores for data will be created
13
+ # for each MySQL server instance. This should agree with the
14
+ # per server'data_dir' property in the servers.yml file, and it should
15
+ # also agree with the 'datadir' property in the server's configuration
16
+ # file (my*.cnf).
17
+ DATA_HOME = "/opt/MySQL/instances"
18
+
19
+ # The home directory of Continuent's open source replicator. Eventually,
20
+ # a command will be added to this script to switch between MySQL native
21
+ # replication and Continuent's open-source Tungsten replicator.
22
+ REPLICATOR_HOME = "/opt/continuent/replicator"
23
+
24
+ # For simplicity, we're using the load-generator/benchmarker that comes
25
+ # in the Continuent source package. This may be replaced with sql-bench
26
+ # from the MySQL source distribution.
27
+ BENCHMARK = "#{REPLICATOR_HOME}/bristlecone/bin/benchmark.sh"
28
+ BENCHMARK_PROPERTIES = File.expand_path("../bristlecone.properties", __FILE__)
29
+
30
+ # Set this to the directory where you want dump files to be stored.
31
+ DUMP_DIR = "#{DATA_HOME}/dump"
32
+
33
+ # The default name of the dump file in the DUMP_DIR directory.
34
+ DEFAULT_DUMPFILE = "dbdump.db"
35
+
36
+ # User name and password for the replication account, used only internally by
37
+ # the replication processes.
38
+ REPLICATION_USER = "repl"
39
+ REPLICATION_PASSWORD = "secret"
40
+
41
+ # Replication account is set up as %.#{REPLICATION_DOMAIN}.
42
+ REPLICATION_DOMAIN = "thirdmode.com"
43
+
44
+ # A minor convenience.
45
+ DEFAULT_MASTER = 1
46
+
47
+ # Typically, this is of the form #{HOSTNAME}-relay-bin'.
48
+ RELAY_LOG = "deimos-relay-bin"
49
+ end
50
+ end