jerbil 1.2.2

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.
Files changed (86) hide show
  1. data/Bugs.rdoc +66 -0
  2. data/Gemfile +12 -0
  3. data/History.txt +359 -0
  4. data/Intro.txt +5 -0
  5. data/LICENCE.rdoc +159 -0
  6. data/README.md +335 -0
  7. data/README_SERVICES.md +410 -0
  8. data/README_TESTING.md +47 -0
  9. data/bin/jerbil +62 -0
  10. data/bin/jerbil-install +56 -0
  11. data/etc/conf.d/jerbild +15 -0
  12. data/etc/conf.d/jserviced +39 -0
  13. data/etc/init.d/jerbild +55 -0
  14. data/etc/init.d/jserviced +59 -0
  15. data/etc/jerbil/jerbil-client.rb +2 -0
  16. data/etc/jerbil/jerbil.rb +83 -0
  17. data/lib/jerbil.rb +636 -0
  18. data/lib/jerbil/config.md +49 -0
  19. data/lib/jerbil/config.rb +67 -0
  20. data/lib/jerbil/errors.rb +74 -0
  21. data/lib/jerbil/jerbil_service/base.rb +191 -0
  22. data/lib/jerbil/jerbil_service/client.rb +325 -0
  23. data/lib/jerbil/jerbil_service/config.md +119 -0
  24. data/lib/jerbil/jerbil_service/config.rb +72 -0
  25. data/lib/jerbil/jerbil_service/sclient.rb +343 -0
  26. data/lib/jerbil/jerbil_service/support.rb +58 -0
  27. data/lib/jerbil/jerbil_service/utils.rb +35 -0
  28. data/lib/jerbil/servers.rb +230 -0
  29. data/lib/jerbil/service.rb +216 -0
  30. data/lib/jerbil/support.rb +160 -0
  31. data/lib/jerbil/thor/server.rb +76 -0
  32. data/lib/jerbil/thor/service.rb +74 -0
  33. data/lib/jerbil/version.rb +13 -0
  34. data/sbin/jerbil-status +120 -0
  35. data/sbin/jerbil-stop +139 -0
  36. data/sbin/jerbild +186 -0
  37. data/sbin/jservice-status +107 -0
  38. data/sbin/jservice-stop +94 -0
  39. data/sbin/jserviced +111 -0
  40. data/spec/jerbil_2_jerbil_spec.rb +87 -0
  41. data/spec/jerbil_client1_spec.rb +80 -0
  42. data/spec/jerbil_client_spec.rb +114 -0
  43. data/spec/jerbil_client_stop_spec.rb +24 -0
  44. data/spec/jerbil_daemonised/jerbil_local_spec.rb +81 -0
  45. data/spec/jerbil_daemonised/jerbil_remote_spec.rb +116 -0
  46. data/spec/jerbil_load.rb +48 -0
  47. data/spec/jerbil_local_spec.rb +91 -0
  48. data/spec/jerbil_missing_spec.rb +98 -0
  49. data/spec/jerbil_remote_spec.rb +117 -0
  50. data/spec/jerbil_remote_spec_bup.rb +168 -0
  51. data/spec/jerbil_service_error_spec.rb +56 -0
  52. data/spec/jerbil_service_spec.rb +41 -0
  53. data/spec/jerbil_support_spec.rb +69 -0
  54. data/spec/jservice_utils_spec.rb +38 -0
  55. data/spec/server_spec.rb +69 -0
  56. data/spec/server_update_spec.rb +28 -0
  57. data/spec/service_spec.rb +72 -0
  58. data/spec/spec_helper.rb +12 -0
  59. data/spec/test_env_spec.rb +53 -0
  60. data/test/bad_test_service.rb +31 -0
  61. data/test/conf.d/jerbil +36 -0
  62. data/test/conf.d/jerbil.conf +39 -0
  63. data/test/conf.d/jerbil.rb +55 -0
  64. data/test/conf.d/jerbil_local.rb +33 -0
  65. data/test/conf.d/jerbil_no_local.conf +39 -0
  66. data/test/conf.d/jerbil_old.rb +47 -0
  67. data/test/conf.d/jerbil_test.rb +35 -0
  68. data/test/conf.d/malformed +1 -0
  69. data/test/conf.d/missing_services +39 -0
  70. data/test/conf.d/ruby_test.rb +8 -0
  71. data/test/init.d/jerbild +14 -0
  72. data/test/jerbil.rb +51 -0
  73. data/test/jerbil_config.rb +8 -0
  74. data/test/jstop.rb +36 -0
  75. data/test/key.asc +1 -0
  76. data/test/lib/ruby_test.rb +37 -0
  77. data/test/lib/ruby_test/config.rb +56 -0
  78. data/test/lib/ruby_test/version.rb +13 -0
  79. data/test/pids/jerbil-prod.asc +1 -0
  80. data/test/pids/jerbil-prod.pid +1 -0
  81. data/test/pids/jerbil.pid +1 -0
  82. data/test/private_key_file.asc +3 -0
  83. data/test/service-stop.rb +86 -0
  84. data/test/service_mock.rb +94 -0
  85. data/test/test_service_client.rb +25 -0
  86. metadata +265 -0
@@ -0,0 +1,119 @@
1
+ # JerbilService::Config Parameters
2
+
3
+ The following parameters are defined in {JerbilService::Config} and should be used
4
+ in a configuration file. A default config file can be generated using:
5
+
6
+ jeckyl config lib/jerbil/jerbil_service/config.rb
7
+
8
+ ## Parameters
9
+
10
+ * **environment**
11
+
12
+ Set the environment for the service to run in.
13
+
14
+ Can be one of the following:
15
+ :prod - for productionised services in use across a network
16
+ :test - for testing a release candidate, e.g. also across the network
17
+ :dev - for developing the next release
18
+
19
+ Services can be running in all three environments at the same time. Clients
20
+ will need to use the appropriate config file to connect with each environment.
21
+
22
+ Default: :prod
23
+
24
+ * **key_dir**
25
+
26
+ a writable directory where Jerbil stores a private key for each service.
27
+ This key is used to authenticate systems operations, such as stopping the service.
28
+ It is not used for client interactions, which can require a separate service key.
29
+
30
+ Default: "/var/run/jerbil"
31
+
32
+ * **jerbil_env**
33
+
34
+ Set this only to use a Jerbil Server that is not running in the production environment
35
+
36
+ No default set
37
+
38
+ * **pid_dir**
39
+
40
+ A writable directory used to store the pid to assist in stopping reluctant servers
41
+
42
+ Default: "/var/run/jerbil"
43
+
44
+ ## Additional Parameters from Jellog::Config
45
+
46
+ The following additional parameters are defined in Jellog::Config, which
47
+ is an ancestor of this config class. See separate documentation for more details.
48
+
49
+ ### Parameters
50
+
51
+ * **disable_syslog**
52
+
53
+ Set to true to prevent system log calls from logging to syslog as well
54
+
55
+ Default: false
56
+
57
+ * **log_date_time_format**
58
+
59
+ Format string for time stamps. Needs to be a string that is recognised by String#strftime
60
+ Any characters not recognised by strftime will be printed verbatim, which may not be what you want
61
+
62
+ Default: "%Y-%m-%d %H:%M:%S"
63
+
64
+ * **log_rotation**
65
+
66
+ Number of log files to retain at any time, between 0 and 20
67
+
68
+ Default: 2
69
+
70
+ * **log_length**
71
+
72
+ Size of a log file (in MB) before switching to the next log, upto 20 MB
73
+
74
+ Default: 1
75
+
76
+ * **log_dir**
77
+
78
+ Path to a writeable directory where Jellog will save log files.
79
+
80
+ Default: "/var/log/jellog"
81
+
82
+ * **log_coloured**
83
+
84
+ Set to false to suppress colourful logging. Default colours can be changed by calling
85
+ #colours= method
86
+
87
+ Default: true
88
+
89
+ * **log_sync**
90
+
91
+ Setting to true (the default) will flush log messages immediately, which is useful if you
92
+ need to monitor logs dynamically
93
+
94
+ Default: true
95
+
96
+ * **log_level**
97
+
98
+ Controls the amount of logging done by Jellog
99
+
100
+ * :system - standard message, plus log to syslog
101
+ * :verbose - more generous logging to help resolve problems
102
+ * :debug - usually used only for resolving problems during development
103
+
104
+
105
+ Default: :system
106
+
107
+ * **log_reset**
108
+
109
+ Reset the logfile when starting logging by setting to true, otherwise append to
110
+ existing log
111
+
112
+ Default: false
113
+
114
+ * **log_mark**
115
+
116
+ Set the string to be used for marking the log with logger.mark
117
+
118
+ Default: " ===== Mark ====="
119
+
@@ -0,0 +1,72 @@
1
+ #
2
+ # Template for Jerbil Service Config
3
+ #
4
+ # Author:: Robert Sharp
5
+ # Copyright:: Copyright (c) 2011 Robert Sharp
6
+ # License:: Open Software Licence v3.0
7
+ #
8
+ # This software is licensed for use under the Open Software Licence v. 3.0
9
+ # The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
10
+ # and in the file copyright.txt. Under the terms of this licence, all derivative works
11
+ # must themselves be licensed under the Open Software Licence v. 3.0
12
+ #
13
+ # Use this template to create a service config file by adapting a copy of the jeckly_generate_config
14
+ # utility.
15
+ #
16
+ require 'jellog/config'
17
+
18
+
19
+ module JerbilService
20
+
21
+
22
+ # configuration options for a Jerbil Service, which includes the Jellog logger and therefore
23
+ # inherits Jellog's options first.
24
+ #
25
+ # @see file:lib/jerbil/jerbil_service/config.md Jerbil Service Parameter Descriptions
26
+ #
27
+ class Config < Jellog::Config
28
+
29
+ def configure_environment(env)
30
+
31
+ default :prod
32
+ comment "Set the environment for the service to run in.",
33
+ "",
34
+ "Can be one of the following:",
35
+ " :prod - for productionised services in use across a network ",
36
+ " :test - for testing a release candidate, e.g. also across the network",
37
+ " :dev - for developing the next release",
38
+ "",
39
+ "Services can be running in all three environments at the same time. Clients",
40
+ "will need to use the appropriate config file to connect with each environment."
41
+
42
+ env_set = [:prod, :test, :dev]
43
+ a_member_of(env, env_set)
44
+
45
+ end
46
+
47
+ def configure_key_dir(path)
48
+ default '/var/run/jerbil'
49
+ comment "a writable directory where Jerbil stores a private key for each service.",
50
+ "This key is used to authenticate systems operations, such as stopping the service.",
51
+ "It is not used for client interactions, which can require a separate service key."
52
+
53
+ a_writable_dir(path)
54
+ end
55
+
56
+ def configure_pid_dir(path)
57
+ default '/var/run/jerbil'
58
+ comment "A writable directory used to store the pid to assist in stopping reluctant servers"
59
+
60
+ a_writable_dir(path)
61
+ end
62
+
63
+ def configure_jerbil_env(env)
64
+ comment "Set this only to use a Jerbil Server that is not running in the production environment"
65
+ env_set = [:prod, :test, :dev]
66
+ a_member_of(env, env_set)
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,343 @@
1
+ #
2
+ # Description
3
+ #
4
+ # Author:: Robert Sharp
5
+ # Copyright:: Copyright (c) 2010 Robert Sharp
6
+ # License:: Open Software Licence v3.0
7
+ #
8
+ # This software is licensed for use under the Open Software Licence v. 3.0
9
+ # The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
10
+ # and in the file copyright.txt. Under the terms of this licence, all derivative works
11
+ # must themselves be licensed under the Open Software Licence v. 3.0
12
+ #
13
+ #
14
+ require 'rubygems'
15
+ require 'daemons'
16
+ require 'drb'
17
+ require 'socket'
18
+
19
+ require 'jellog'
20
+ require 'jerbil/support'
21
+ require 'jerbil/servers'
22
+ require 'jeckyl/errors'
23
+
24
+ module JerbilService
25
+
26
+ # Supervisor (Supervisory Client) - a wrapper class for managing a Jerbil Service
27
+ #
28
+ # Can be used to create a daemon script for a service. First gather options
29
+ # from the command line using optparse and then call Supervisor.new. Within the block
30
+ # call the methods below in response to the options on the command line. When the
31
+ # block closes the service will be started and will wait for calls.
32
+ #
33
+ # All of this is already done for you by /usr/sbin/jserviced.
34
+ # See {file:README_SERVICES.md Services Readme} for more details.
35
+ #
36
+ class Supervisor
37
+
38
+ # create and run a service daemon for the given class, which should be a JerbilService
39
+ # class.
40
+ #
41
+ # The service called through this supervisor needs to comply with Jerbil naming
42
+ # conventions. This requires the service to be defined within a module with the
43
+ # name of the service, and having a class called Service within it. See
44
+ # {file:README_SERVICES.md Service Readme} for more details.
45
+ #
46
+ # The method yields a block. Within the block, use the methods below to set parameters and the service
47
+ # will then be launched when the block returns:
48
+ #
49
+ # JerbilService::Supervisor.new(MyService, opts) do |service|
50
+ # service.no_daemon
51
+ # service.quiet
52
+ # end
53
+ #
54
+ # The supervisor will start the service when the block exits.
55
+ #
56
+ #
57
+ # @param [Module] klass is the service module (see above)
58
+ # @yield [service] instance of supervisor to config
59
+ def initialize(klass, &block)
60
+
61
+ @daemonize = true
62
+ @config_file = nil
63
+ @verbose = false
64
+ @quiet = false
65
+ @no_syslog = false
66
+ @output = $stderr
67
+ @logger = nil
68
+ @set_log_daemon = false # flag to log the daemon itself
69
+ @jerbil_env = nil
70
+ @klass = klass
71
+ @name = klass.to_s.downcase
72
+ @name_symbol = @name.to_sym
73
+
74
+ # only called without a block internally to effect the stop
75
+ # see below
76
+ if block_given? then
77
+ block.call(self)
78
+ else
79
+ return self # created for stop
80
+ end
81
+
82
+ # only gets here for a start
83
+ self.start_service
84
+
85
+ end
86
+
87
+ # start the service without daemonising
88
+ def no_daemon
89
+ @daemonize = false
90
+ end
91
+
92
+ # output extra information about starting up the service. Ignored if quiet has been set
93
+ # Note this controls messages from the Supervisor about the startup process
94
+ # and is unrelated to the service's logger
95
+ def verbose
96
+ @verbose = true unless @quiet
97
+ end
98
+
99
+ # output absolutely nothing
100
+ def quiet
101
+ @quiet = true
102
+ @verbose = false
103
+ @output = File.open('/dev/null', 'w')
104
+ end
105
+
106
+ # ensure logging does not log to syslog
107
+ # see Jellog::Logger#disable_syslog for details
108
+ def no_syslog
109
+ @no_syslog = true
110
+ end
111
+
112
+ # set the config file for the service. Each service expects an options hash, which the supervisor
113
+ # will obtain from either this file, or the default, which is usually: /etc/jermine/<service>.rb
114
+ def config_file=(cfile)
115
+ @config_file = cfile
116
+ end
117
+
118
+ # set the supervisor output to a file
119
+ # @param [IO] ofile is a file object to output to
120
+ def output=(ofile)
121
+ @output = ofile unless @quiet
122
+ end
123
+
124
+ # create a log file for the daemon task, the output of
125
+ # which is otherwise lost. This uses jellog and will write the log
126
+ # to a file in the log_dir (see {JerbilService::Config}) named after the service with _sd added.
127
+ # By default this would be /var/log/jermine/<service>_sd.log
128
+ #
129
+ # This logger takes over from the output file set in {JerbilService::Supervisor#output}, but only
130
+ # when the supervisor daemonises.
131
+ #
132
+ def log_daemon
133
+ @set_log_daemon = true
134
+ end
135
+
136
+ # override the default jerbil config file, used only
137
+ # for testing new versions of jerbil
138
+ #
139
+ # @deprecated - jerbil_env is a standard config parameter now, although still only
140
+ # intended for test purposes.
141
+ def jerbil_env=(env)
142
+ @jerbil_env = env
143
+ end
144
+
145
+
146
+ # this class method if called to create an instance of the supervisor to
147
+ # stop a Jerbil service. Use the methods above in the block to set
148
+ # parameters, although some of them have no meaning in this context.
149
+ #
150
+ # @param [Module] klass is the service module of the service to stop
151
+ # @yield [service] instance of supervisor to config
152
+ def self.stop(klass, &block)
153
+
154
+ # create an instance of this class without starting the service
155
+ # (no block)
156
+ sclient = self.new(klass)
157
+
158
+ block.call(sclient)
159
+
160
+ sclient.stop_service
161
+
162
+ end
163
+
164
+
165
+ # @private
166
+ # this method is called by the initialize method to start a Jerbil Service
167
+ # messages are logged through @output, which is stderr by default or
168
+ # /dev/null if quiet was enabled, or a Jellog logger.
169
+ #
170
+ def start_service
171
+
172
+ @output.puts "Welcome to #{@klass.to_s} (#{@klass.ident})"
173
+
174
+ # get the config options for this service
175
+ config = @klass.get_config(@config_file)
176
+
177
+ # create a hash for logger options
178
+ log_opts = {}
179
+
180
+ # to test a new jerbil server, this needs to be set to the
181
+ # jerbil server's environment. Only needed for test purposes
182
+ if @jerbil_env then
183
+ config[:jerbil_env] = @jerbil_env
184
+ end
185
+
186
+ # create a Jellog logging object if requested
187
+ # if @set_log_daemon then
188
+ # Jellog::Logger.disable_syslog if @no_syslog
189
+ # log_opts = Jellog::Logger.get_options(config)
190
+ # log_opts[:log_level] = :debug if @verbose
191
+ # @logger = Jellog::Logger.new("#{@klass.to_s.downcase}_sd", log_opts)
192
+ # @output.puts "Logging output to #{@logger.logfilename}"
193
+ # @output.flush
194
+ # @output = @logger
195
+ # end
196
+
197
+ # log the configuration options if requested
198
+ if @verbose then
199
+ @output.puts "Obtained configuration options"
200
+ config.each_pair do |key, value|
201
+ @output.puts " :#{key} => #{value}"
202
+ end
203
+ end
204
+
205
+ @output.puts "Running Service in environment: #{config[:environment]}"
206
+
207
+ # create a private key for the service
208
+ pkey = Jerbil::Support.create_private_key(@name_symbol, config[:environment], config[:key_dir])
209
+
210
+ @output.puts "Created a private key in: #{config[:key_dir]}" if @verbose
211
+
212
+ # the service will be daemonized so need to set up daemon parameters
213
+ if @daemonize then
214
+ @output.puts "About to demonize this service"
215
+ # cleanly close everything
216
+ #@output.close
217
+
218
+ dopts = {:backtrace=>true,
219
+ :app_name=>@klass.to_s.downcase + "_daemon",
220
+ :log_dir=>config[:log_dir],
221
+ :log_output=>true,
222
+ :dir_mode=>:normal,
223
+ :dir=>config[:log_dir]}
224
+ Daemons.daemonize(dopts)
225
+
226
+ # all those open files are closed?
227
+ # so open the logger again
228
+ if @set_log_daemon then
229
+ log_opts = Jellog::Config.intersection(config)
230
+ log_opts[:log_level] = :debug if @verbose
231
+ @output = Jellog::Logger.new("#{@klass.to_s.downcase}_sd", log_opts)
232
+ else
233
+ # no logger, so write any messages to /dev/null
234
+ @output = File.open('/dev/null', 'w')
235
+ end
236
+
237
+ else
238
+ @output.puts "Service is running in the foreground"
239
+ end
240
+
241
+ if @no_syslog then
242
+ @output.puts "Disabling messages to syslog"
243
+ Jellog::Logger.disable_syslog
244
+ else
245
+ @output.puts "Sending messages to syslog"
246
+ end
247
+
248
+ # now create the pid file
249
+ Jerbil::Support.write_pid_file(@name_symbol, config[:environment], config[:pid_dir])
250
+
251
+ @output.puts "Created a pid file for process: #{Process.pid}"
252
+
253
+ @service = @klass::Service.new(pkey, config)
254
+
255
+ @output.puts "Registered Service with Jerbil"
256
+
257
+ @service.wait(pkey)
258
+
259
+ @output.puts "Service has stopped"
260
+
261
+ rescue => err
262
+ puts "Error while starting service: #{err.class.to_s}, #{err.message}"
263
+ puts err.backtrace.join("\n") if @verbose
264
+ end
265
+
266
+ # @private stop a Jerbil Service
267
+ def stop_service
268
+
269
+ config = @klass.get_config(@config_file)
270
+ pid = 0
271
+
272
+ # to test a new jerbil server, this needs to be set to the
273
+ # jerbil server's environment. Only needed for test purposes
274
+ if @jerbil_env then
275
+ config[:jerbil_env] = @jerbil_env
276
+ end
277
+
278
+ if @verbose then
279
+ @output.puts "Obtained configuration options"
280
+ config.each_pair do |key, value|
281
+ @output.puts " :#{key} => #{value}"
282
+ end
283
+ end
284
+
285
+ @output.puts "Stopping Service #{@klass.to_s} in environment: #{config[:environment]}"
286
+ pkey = Jerbil::Support.get_key_and_delete_file(@name_symbol, config[:environment], config[:key_dir])
287
+ pid = Jerbil::Support.get_pid_and_delete_file(@name_symbol, config[:environment], config[:pid_dir])
288
+
289
+ service_opts = {:name=>@name_symbol, :env=>config[:environment]}
290
+ service_opts[:host] = Socket.gethostname
291
+
292
+ begin
293
+ # find jerbil
294
+ jerbil_server = Jerbil::Servers.get_local_server(config[:jerbil_env])
295
+
296
+ # now connect to it
297
+ jerbil = jerbil_server.connect
298
+
299
+ # and get service
300
+ my_service = jerbil.get(service_opts)
301
+
302
+ if my_service.nil? then
303
+ @output.puts "Cannot find service through Jerbil"
304
+ end
305
+
306
+ session = my_service.connect
307
+
308
+ rescue Jerbil::MissingServer
309
+ @output.puts("Cannot find a local Jerbil server")
310
+ rescue Jerbil::JerbilConfigError => err
311
+ @output.puts("Error in Jerbil Config File: #{err.message}")
312
+ rescue Jerbil::JerbilServiceError =>jerr
313
+ @output.puts("Error with Jerbil Service: #{jerr.message}")
314
+ rescue Jerbil::ServerConnectError
315
+ @output.puts("Error connecting to Jerbil Server")
316
+ end
317
+
318
+ # now to do the stopping
319
+ begin
320
+ session.stop_callback(pkey)
321
+ @output.puts "Stopped service successfully"
322
+ rescue DRb::DRbConnError
323
+ @ouput.puts "Service stopped, but not gracefully"
324
+ return nil
325
+ end
326
+
327
+ rescue Jeckyl::JeckylError => jerr
328
+ @output.puts "Error in Configuration file: #{jerr.message}"
329
+ # there is no pid, so just exit
330
+ rescue => err
331
+ @output.puts "Error while stopping service: #{err.message}"
332
+ @output.puts err.backtrace if @verbose
333
+ # it went wrong, so fall back on pid killing
334
+ if pid > 0 then
335
+ @output.puts "Killing the process: #{pid}"
336
+ Process.kill("SIGKILL", pid)
337
+ else
338
+ @output.puts "No pid available - nothing to kill"
339
+ end
340
+ end
341
+ end
342
+
343
+ end