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,335 @@
1
+ # Jerbil
2
+
3
+ **(a.k.a Jumpin Ermin's Reliable Broker for Integrated Linux services)**
4
+
5
+ An Object Broker for ruby that provides reliable access to services across the LAN
6
+ and comes complete with a service class that makes writing services easy, hiding all
7
+ of the broker interactions.
8
+
9
+ **GitHub:** [https://github.com/osburn-sharp/jerbil](https://github.com/osburn-sharp/jerbil)
10
+
11
+ **RubyDoc:** [http://rubydoc.info/github/osburn-sharp/jerbil/frames](http://rubydoc.info/github/osburn-sharp/jerbil/frames)
12
+
13
+ **RubyGems:** [https://rubygems.org/gems/jerbil](https://rubygems.org/gems/jerbil)
14
+
15
+ See Also:
16
+
17
+ * {file:README_SERVICES.md Services Readme} for details about how to create a service that
18
+ uses the Jerbil Server
19
+ * {file:README_TESTING.md Testing Readme} for a note about testing Jerbil and Jerbil Services
20
+
21
+ ## Installation
22
+
23
+ ### Note
24
+
25
+ Jerbil will work on any Linux distro (and possibly other systems too) but it comes with
26
+ all the gear necessary to work on Gentoo out of the box - e.g. runscripts, /etc/conf.d files
27
+ and the like.
28
+
29
+ ### Installing the Gem
30
+
31
+ Jerbil is available as a gem, so to get the gem:
32
+
33
+ # gem install jerbil
34
+
35
+ Jerbil needs extra files to be installed on the system, which is done with the help
36
+ of [Jeni](https://github.com/osburn-sharp/jeni):
37
+
38
+ # jerbil-install
39
+
40
+ This will install various files over and above those installed by the gem, including configuration files,
41
+ runscripts, and sbin wrappers for the jerbil server and for services that use the server.
42
+ Use the -p switch to pretend and see if everything works OK. Jerbil assumes there is a
43
+ user 'jerbil' that will run the server process etc, so if there is no user 'jerbil' then
44
+ this script will create one.
45
+
46
+ Jerbil can also be installed from source by downloading from GitHub (see above).
47
+
48
+ ### System Architecture Overview
49
+
50
+ A Jerbil Server should be run on every machine that uses or provides services through
51
+ Jerbil. The servers self-discover each other and share service records so that the loss
52
+ of a single node in the network does not disrupt the rest of the network. The system is
53
+ not secure, but all servers share a secret key and check for this key before accepting
54
+ other servers into the network. Its more to avoid mistakes than proper security.
55
+
56
+ Services always register with their local server and clients always request
57
+ services from their local server. If services inherit the {JerbilService::Base} class all server interactions
58
+ are hidden from the user and if clients use the {JerbilService::Client} class then all server interactions
59
+ are also hidden. Service startup and shutdown can be achieved through a common script making it easy to
60
+ bring a new service into operation.
61
+
62
+ All services (and servers) can be run in one of three environments: prod, test and dev. This allows
63
+ development versions to run in parallel with production versions etc.
64
+
65
+ ### Configuration
66
+
67
+ The configuration file for the server (jerbil.rb) will be placed in a directory /etc/jerbil. As well as checking
68
+ the defaults, you need to generate a secret. A random secret can be generated using the jerbil command:
69
+
70
+ # jerbil server secret
71
+
72
+ although any long string will do. Full details of the configuration parameters for Jerbil are in {Jerbil::Config}.
73
+
74
+ ### Editting /etc/services
75
+
76
+ Jerbil uses /etc/services to find its services (unsurprisingly) so this file needs to be updated. There must
77
+ be an entry for the server itself, as well as the services that use jerbil. Because Jerbil supports three
78
+ operating environments (dev, test and prod), these services must be assigned in triplets. The following is an example
79
+
80
+ # starts from 49195
81
+ #
82
+ jerbil 49200/tcp # Jerbil Server
83
+ jerbil-test 49201/tcp
84
+ jerbil-dev 49202/tcp
85
+
86
+ jexten 49203/tcp # Jexten Service - controls CM15pro
87
+ jexten-test 49204/tcp
88
+ jexten-dev 49205/tcp
89
+
90
+ tittle 49206/tcp # Tittle - Thermostatic Temperature Logger
91
+ tittle-test 49207/tcp
92
+ tittle-dev 49208/tcp
93
+
94
+ tittledm 49209/tcp # Tittle's little device manager service
95
+ tittledm-test 49210/tcp
96
+ tittledm-dev 49211/tcp
97
+
98
+ jemb 49212/tcp # Jumpin' Ermin's Music Box
99
+ jemb-test 49213/tcp
100
+ jemb-dev 49214/tcp
101
+
102
+ Strictly speaking the intermediate assignments do not need to be defined: Jerbil looks for the first one
103
+ and offsets it if either test or dev is selected. They are included here as a reminder that the ports may be used.
104
+
105
+ ### Starting and Stopping the Server
106
+
107
+ Once you have generated a secret and set up some services in /etc/services, it is now possible to
108
+ start the Jerbil Server. This can be done using the jerbild script:
109
+
110
+ # /usr/sbin/jerbild
111
+
112
+ which will start the server, get the default config file (/etc/jermine/jerbil.rb), daemonise, and say very little.
113
+ If you add the -h or --help switch you can see how to overide this default behaviour.
114
+ You can then test that the server is running with:
115
+
116
+ # jerbil server
117
+
118
+ If this does not report the server as up, go to the troubleshooting section.
119
+
120
+ If you can support init scripts, then jerbil is ready to go. Edit /etc/conf.d/jerbild if you need to change settings such as
121
+ where the config file is and then run:
122
+
123
+ # /etc/init.d/jerbild start
124
+ # rc-update add jerbild default
125
+
126
+ the latter command works on Gentoo at least.
127
+
128
+ You can also check if the server is working using:
129
+
130
+ # /usr/sbin/jerbil-status -V
131
+ or
132
+ # /etc/init.d/jerbild status
133
+
134
+ To stop the server:
135
+
136
+ # /usr/sbin/jerbil-stop
137
+ or
138
+ # /etc/init.d/jerbild stop
139
+
140
+ Further details of all these commands can be obtained with the -h or --help option
141
+
142
+
143
+ ## General Description
144
+
145
+ The function of Jerbil is to make it easy to write linux services in ruby that can be deployed anywhere on
146
+ a network, once or multiple times, and enabling clients to access these services regardless of where they are. Its
147
+ a wrapper around DRb and a replacement for Rinda.
148
+
149
+ A Jerbil Server is required to run on each machine where services are needed or from which they are accessed.
150
+ Each server will discover other servers on the network and register with them, provided they all share the same
151
+ secret and are running in the same environment. During registration, new servers will receive details from the other
152
+ servers of all the services that are local to them. This provides a robust and relatively self-healing network where
153
+ a server can come and go without needing to restart any of the others. By comparison, the Rinda server presents a
154
+ single point of failure. If it goes down nobody can find anything and all services have to be restarted when the
155
+ server is restored.
156
+
157
+ Part of the self-healing in Jerbil is dealing with services that become unavailable. When this happens, the server
158
+ checks if the services local server is running. If it is, this local server is asked to deal with the missing service
159
+ and update the database accordingly. If it is not, then the original server takes responsibility for the missing
160
+ service and purges it from all the other servers.
161
+
162
+ A Service registers with a server to make its services available. A client then searches the server for the service(s)
163
+ it is interested in and receives back all of the matching services known. The client can then connect to each service
164
+ and carry out whatever action is required. The search can be controlled, e.g. to return only local services or the first
165
+ service or services in a given environment.
166
+
167
+ Writing a Service is eased by various support classes. The main class is {JerbilService::Base}, which is a generic service
168
+ that deals with all of the Jerbil server interactions. By inheriting this class, a service can be created that uses
169
+ Jerbil with only a couple of lines of code.
170
+
171
+ Controlling a service is also made easy by the {JerbilService::Supervisor} class. This hides all of the actions needed
172
+ to start a service. However, service control is made even easier by /usr/bin/jserviced, which starts any service
173
+ given that services name, provided the files conform to certain protocols. The /usr/sbin/jservice-status and
174
+ /usr/sbin/jservice-stop commands work in a similar manner.
175
+
176
+ Writing a client is similarly made easy by the {JerbilService::Client} class, which finds one or more services ready
177
+ to be connected to and acted upon.
178
+
179
+ ### Further Reading
180
+
181
+ * {file:README_SERVICES.md Jerbil Services} A short guide.
182
+
183
+ ## Code Walkthrough
184
+
185
+ The Jerbil code is available online at [GitHub](https://github.com/osburn-sharp/jerbil)
186
+ Jerbil is divided into two groups: the server and the services that use the server.
187
+
188
+ ### Servers
189
+
190
+ The server consists of one main class: {Jerbil::Broker} and two data-type classes:
191
+ {Jerbil::Servers} and {Jerbil::ServiceRecord}. The Broker contains the main server code,
192
+ finding and registering with other servers, accepting and recording services and
193
+ responding to queries about registered services. When a service registers with
194
+ the broker, the broker will also inform all of the other servers of that service.
195
+ The {Jerbil::Servers} class is used by the broker to record information
196
+ about a server and it provides convenience methods to connect to a server and a class
197
+ method to find the local server. The {Jerbil::ServiceRecord} class fulfils a similar
198
+ role for services.
199
+
200
+ When a server starts up it uses the {Jerbil::Servers.find_servers} class method to
201
+ search the network for any other servers. This method uses the NetAddr gem to create a
202
+ list of network addresses from the parameters defined by {Jerbil::Config}, allowing
203
+ users to limit jerbil addresses, both to control which machines get polled and to speed
204
+ up the search. The jerbil port is polled using the standard library TCPSocket interface
205
+ with a timeout (standard library again). When the server finds another server it first
206
+ does a minor security check (see below) and then obtains all of the services registered with
207
+ that server and adds it to its service database.
208
+
209
+ Jerbil is intended to be as reliable as possible - to survive any of the servers and
210
+ their services leaving the network unexpectedly. If a local client attempts to connect
211
+ to a remote service and fails, then the server will be asked to check with {Jerbil::Broker#service_missing?}.
212
+ This will attempt to contact the service's local server and ask it to check. If
213
+ the local server is running, it will check that the service is OK and if not, remove
214
+ the service and update all the other servers. If this server is not available (e.g.
215
+ server has gone down) then the original server will take responsibility for purging the
216
+ service from its own records and all the remaining servers.
217
+
218
+ Jerbil uses Jellog for logging and on :debug level produces copious records to help understand
219
+ what it is doing. See below for more detail on Jerbil logging.
220
+
221
+ Jerbil and Jerbil Services use the standard library daemons to run in the background
222
+ but they keep track of their own pids instead of relying on daemon. To stop the server,
223
+ an attempt is made to call the stop method, which cleans up with all the other servers,
224
+ but failing that the pid is used to kill the server.
225
+
226
+ ### Services
227
+
228
+ Services are created by inheriting the {JerbilService::Base} class:
229
+
230
+ module RubyTest
231
+
232
+ extend JerbilService::Support
233
+
234
+ class Service < JerbilService::Base
235
+
236
+ def initialize(pkey, options)
237
+ super(:rubytest, pkey, options)
238
+ end
239
+
240
+ def action
241
+ @logger.debug("Someone called the action method!")
242
+ return "Hello"
243
+ end
244
+
245
+ end
246
+
247
+ end
248
+
249
+ The Base class takes care of Jerbil registration and creates a Jellog logger instance variable. It also provides a stop
250
+ method and a verify method. Full details on creating Jerbil Services are provided in the {file:README_SERVICES.md Readme file}.
251
+
252
+ ### Security
253
+
254
+ Security is currently limited:
255
+
256
+ * Servers share a secret key, recorded in their config file which should be readable by limited people! They use this
257
+ key to ensure that registering servers are bona fide.
258
+
259
+ * Each server is given its own session-unique private key that it shares with the others and checks for all of the remote server methods.
260
+ The same key is also required to stop the server.
261
+
262
+ * A similar key is provided to each service and is required to stop the service. It is up to service writers to decide
263
+ whether to require clients to use this key, but a check_key method is provided.
264
+
265
+ The purpose of these checks is largely to protect integrity rather than make Jerbil secure. Jerbil is currently
266
+ targetted at a benign network environment.
267
+
268
+ During installation, jerbil-install should have created the 'jermine' user. By default the jerbil servers will run as this
269
+ user and so will any services started using the /etc/init.d runscripts.
270
+
271
+ ### Logging
272
+
273
+ Jerbil uses [Jellog](http://rubydoc.info/github/osburn-sharp/jellog/frames) to log
274
+ messages. By default, these messages will be logged to /var/log/jerbil/jerbil-<env>.log
275
+ where <env> is prod, test or dev depending on the environment jerbil is running in.
276
+ Note that Jellog also logs certain messages to syslog unless you select the option
277
+ to disable this (see sbin/jerbild or /etc/conf.d/jerbild). The verbosity of the log
278
+ can be increased by setting the log_level parameter in {Jerbil::Config} to either
279
+ :verbose or :debug.
280
+
281
+ This log is used by the main Jerbil Server, but it is not the only log generated.
282
+ During start-up, the script will also log to a separate file (by default this is
283
+ /var/log/jerbil/jerbil_sd.log). This can be used to check if something went wrong
284
+ with the script after it daemonised. To ensure that this logging occurs, set the
285
+ command line option for the sbin/jerbild script or the parameter in /etc/conf.d/jerbild.
286
+ Alternatively, run the script in foreground mode to see all the possible messages. This
287
+ is also an option on the script and in the config file.
288
+
289
+ In the event that something goes wrong during the daemonisation itself, the jerbil
290
+ script sets the daemon process to log any messages to a file in the same log directory:
291
+ /var/log/jerbil/jerbil_daemon.output. This can, however, contain a lot of exception
292
+ information that has very little to do with the problem.
293
+
294
+ Finally, if Jerbil fails to start and these logs show no help, it is worth checking
295
+ the file /tmp/jerbil_panic.log which is also created by the startup script in the
296
+ event that an exception is raised during the daemonization process.
297
+
298
+
299
+ ## Dependencies
300
+
301
+ A ruby compiler - works with 1.8.7.
302
+
303
+ Check the {file:Gemfile} for other dependencies.
304
+
305
+ ## Documentation
306
+
307
+ Documentation is best viewed using Yard and is available online
308
+ at [RubyDoc](http://rubydoc.info/github/osburn-sharp/jerbil/frames)
309
+
310
+ ## Testing/Modifying
311
+
312
+ Details of testing can be found in the {file:README_TESTING.md Testing README}.
313
+
314
+ ## Bugs
315
+
316
+ Details of any unresolved bugs and change requests are in {file:Bugs.rdoc Bugs}
317
+
318
+ ## Changelog
319
+
320
+ See {file:History.txt} for a summary change history
321
+
322
+ ## Copyright and Licence
323
+
324
+ Copyright (c) 2012 Robert Sharp
325
+
326
+ This software is licensed under the terms defined in {file:LICENCE.rdoc}
327
+
328
+ The author may be contacted by via [GitHub](http://github.com/osburn-sharp)
329
+
330
+ ## Warranty
331
+
332
+ This software is provided "as is" and without any express or implied
333
+ warranties, including, without limitation, the implied warranties of
334
+ merchantibility and fitness for a particular purpose.
335
+
@@ -0,0 +1,410 @@
1
+ # Jerbil Services
2
+
3
+ A short guide to writing services that use {file:README.md Jerbil}.
4
+
5
+ ## What is Jerbil and why use it?
6
+
7
+ Jerbil provides a way of finding services available on a network (or standlone PC for that matter)
8
+ and connecting with them to use them.
9
+
10
+ For example, I want to run a video recorder service for each TV-card I have on the network,
11
+ and I want to connect these to a central server for scheduling programmes etc. Each service
12
+ registers with Jerbil so that a client can easily find where each service is running,
13
+ select the one needed and connect to it to schedule a specific recording.
14
+
15
+ Jerbil provides the Broker to connect services, but it also provides a framework for
16
+ writing the services and hides almost all of the inter-processor comms from the
17
+ developer. Anyone who has used DRb on its own will know that there is quite a bit of overhead
18
+ involved, made more difficult if you are not sure where the service you want will be running.
19
+ You can use a service like Rinda, but its not exactly reliable: if the server goes down you have
20
+ to restart everything on the network.
21
+
22
+ ## Some Examples of Jerbil Services
23
+
24
+ * An X10 controller - can be used by multiple applications to control X10 devices.
25
+
26
+ * A Thermostatic Temperature Logger - logs temperature data from simple sensors and also
27
+ provides a thermostat that can be programmed to trigger events by remote users
28
+
29
+ * A Central Heating Programmer - capable of controlling multiple devices/zones etc
30
+ using the above services
31
+
32
+ * A Media Player that can be controlled from the web
33
+
34
+ * A Music Player with multiple interfaces (CLI, LIRC, Web) running on multiple PCs to
35
+ share music around the house
36
+
37
+ * A network Disk manager - to show disc status, space etc for the whole network in one
38
+ easy location
39
+
40
+ * A Gentoo Portage Information Service - see what's installed across the network
41
+
42
+ ## Getting Started
43
+
44
+ ### Step 1 - Register your service
45
+
46
+ Before you start, you need to allocate a port number for your service that will be recognised across
47
+ the network. The standard way of doing this is to add it to /etc/services. There are more details
48
+ in the main {file:README.md readme}. Make sure this information is consistent across the network.
49
+
50
+ ### Step 2 - Create a service class
51
+
52
+ The easiest way to develop a service using Jerbil is to inherit the {JerbilService::Base} class.
53
+ That way, all of the registration work is done for you without you even having to worry about it.
54
+ All you need to worry about is what methods you want your service to offer its clients:
55
+
56
+ #(file: lib/my_service.rb)
57
+ require 'jerbil_service/base'
58
+ require 'jerbil_service/support'
59
+
60
+ module MyService
61
+
62
+ # NOTE: make sure you call this class 'Service' if you
63
+ # want to use jerbil's support to run it etc
64
+ #
65
+ class Service < JerbilService::Base
66
+
67
+ # add some additional support class methods into the mix
68
+ extend JerbilService::Support
69
+
70
+ def initialize(pkey, options)
71
+
72
+ # do anything that needs to be done before the
73
+ # DRb service is started
74
+
75
+ # example parameter, see below
76
+ @greeting = options[:welcome]
77
+
78
+ super(:my_service, pkey, options)
79
+
80
+ # Ready to go
81
+ @logger.info "MyService ready to go"
82
+
83
+ end
84
+
85
+ attr_reader :greeting
86
+
87
+ # a method that your service provides
88
+ def whoami
89
+ return "This is my service"
90
+ end
91
+
92
+ end
93
+ end
94
+
95
+ In this very simple example, the service is set up with DRb and registered with the Jerbil
96
+ server when the parent {JerbilService::Base#initialize initialize} method is called. It also sets up a logger using
97
+ Jellog (see dependencies in {file:Gemfile}). After that, clients will be able to find
98
+ the service and call its method.
99
+
100
+ ### Step 3 - Create a config class and file
101
+
102
+ A Jerbil Service expects to be receive a fair few parameters through the options hash passed
103
+ into the initialize method. It would be fairly painful to set this hash manually, but luckily
104
+ it is not necessary if you use [Jeckyl](https://github.com/osburn-sharp/jeckyl). What
105
+ you need to do is to add your own config class that inherits all of the parameters that
106
+ Jerbil is expecting to find:
107
+
108
+ #(file:lib/my_service/config.rb)
109
+ require 'jerbil_service/config'
110
+
111
+ module MyService
112
+
113
+ class Config < JerbilService::Config
114
+
115
+ # define your parameter methods here
116
+
117
+ def configure_welcome(greeting)
118
+ default "Hello and Good Day!"
119
+ comment "Define a welcome greeting for users"
120
+ a_string(greeting)
121
+ end
122
+
123
+ end
124
+ end
125
+
126
+ To find out more about defining parameters, check the Jeckyl documentation on
127
+ [RubyDoc](http://rdoc.info/github/osburn-sharp/jeckyl/frames).
128
+
129
+ There is no hard rule that requires this file to be named as it is, but if you use
130
+ jerbil support (such as jserviced, see below) then this is what it will look for.
131
+ Btw, you can create a template for this file using the jeckyl command:
132
+
133
+ $ jeckyl klass MyService JerbilService::Config
134
+ # echoes template to stdout to ensure you are OK with it
135
+ $ jeckyl klass MyService JerbilService::Config > lib/my_service/config.rb
136
+
137
+ This defines your service-specific parameters and adds them to those that {JerbilService::Base}
138
+ is expecting. You now probably want to create a config file itself:
139
+
140
+ $ jeckyl config lib/my_service/config.rb -k
141
+ # everything looks OK?
142
+ $ jeckyl config lib/my_service/config.rb -k > test/conf.d/my_service.rb
143
+
144
+ The -k option ensures that all of the parameters for all parents are included in the
145
+ config file you have generated. You can now edit the generated config file to tweak
146
+ any of the defaults. For example, you probably want to log you development service
147
+ to a local directory instead of the system default and set the environment to :dev.
148
+
149
+ # Location for Jellog (logging utility) to save log files
150
+ log_dir "/home/user/dev/my_service/log"
151
+
152
+ # Set the default environment for service commands etc.
153
+ #
154
+ # Can be one of :prod, :test, :dev
155
+ environment :dev
156
+
157
+ A small warning - this is Ruby, which does not understand things like "~" in paths.
158
+ For testing, you may want to define a project_root at the top of the config file and
159
+ derive this from the __FILE__ constant. You can check your config file is not going
160
+ to cause you problems again with the jeckyl command:
161
+
162
+ $ jeckyl check test/conf.d/my_service.rb
163
+
164
+ You should now be ready to launch your service.
165
+
166
+ ### Step 4 - Launch the service
167
+
168
+ Jerbil provides a very quick way get your new service up and running: the 'jservice' script:
169
+
170
+ $ /usr/sbin/jserviced -s my_service -c test/conf.d/my_service.rb
171
+
172
+ This script provides a few options to control the way the service is launched:
173
+
174
+ * -n, --no-daemon - do not daemonize the service but run it in the foreground
175
+
176
+ * -l, --log-daemon - log any output from the daemon to its own log-file
177
+
178
+ * -S, --no-syslog - suppress log messages to syslog, i.e. during development of your service
179
+
180
+ * -c, --config - use the given config file instead of the default
181
+
182
+ * -V, --verbose - output more information while setting up the service
183
+
184
+ * -q, --quite - output no information while setting up the service
185
+
186
+ Note that jserviced will expect you to follow ruby gem file-naming conventions so that
187
+ it can locate your service both during testing and in the wild. In this case that
188
+ would mean having a 'lib' directory with a file called 'my_service.rb' containing
189
+ the above code.
190
+
191
+ If you fancy launching your service long-hand, you can use the {JerbilService:Supervisor}
192
+ class to help.
193
+
194
+ ### Step 5 - Check the service is working
195
+
196
+ Use the 'jerbil' command to check that everything is OK:
197
+
198
+ $ jerbil services -v
199
+ There are 13 services registered with Jerbil:
200
+ my_service[:prod]@server.network.org:49203
201
+ my_service[prod]@server.network.org:49203 responded
202
+
203
+ This shows what services are registered and calls each service's {JerbilService::Base#verify verify} method to make sure
204
+ it is running.
205
+
206
+ There is also a script that can be used to check that a service is running: 'sbin/jservice-status'. Options
207
+ are the same as for 'sbin/jserviced' except most of them are ignored.
208
+
209
+ ### Step 6 - Write a Client and run it
210
+
211
+ Connecting to a service from a client is made easy by {JerbilService::Client#find_services}. This hides all
212
+ of the Jerbil interactions and just serves up interfaces as discovered:
213
+
214
+ JerbilService::Client.find_services(:local, MyService, client_opts) do |service|
215
+
216
+ puts service.greeting
217
+ puts service.whoami
218
+
219
+ end
220
+
221
+ This will search Jerbil for the first MyService registered and then call the 'whoami'
222
+ method. You can also find multiple services with the ':all' option, in which case the
223
+ block is called for each retrieved service, or you just find the :first service, which
224
+ is useful when you know there is only one on the network.
225
+
226
+ ### Step 7 - Stopping the service
227
+
228
+ Finally, you will want to stop the service at some point, and better to do this gracefully.
229
+ The most direct way is to use 'sbin/jservice-stop', again with the same options as jserviced.
230
+ This script uses {JerbilService::Supervisor#stop_service} to do the real work, and you can
231
+ use this interface directly if it suits.
232
+
233
+ ## Understanding Services
234
+
235
+ To develop a service using {JerbilService::Base} you probably need to know a little bit more about
236
+ the following:
237
+
238
+ * Jerbil Conventions
239
+ * the options hash, containing various important parameters
240
+ * System methods and how to customise them
241
+ * Keys and PIDS
242
+
243
+ ### Jerbil Conventions
244
+
245
+ The Jerbil support infrastructure makes certain assumptions about how a Jerbil Service project
246
+ is named and structured. Given a service name (e.g. jexten for an X10 controller), there
247
+ should be a module with the same name containing a class called Service that inherits
248
+ {JerbilService::Base}, all within the root gem file (e.g. jexten.rb):
249
+
250
+ (file: jexten.rb)
251
+ module Jexten
252
+
253
+ class Service < JerblService::Base
254
+
255
+ end
256
+
257
+ end
258
+
259
+ In addition, Jerbil expects (by convention) to find a gem subdirectory named after the
260
+ service and containing at least the following files:
261
+
262
+ * errors.rb - defining within the service module a general exception for the service
263
+ and more detailed exceptions inheriting this general exception class.
264
+ * version.rb - defining within the service module three constants: Version containing
265
+ a gem standard version string, Version_Date containing a date string in a format
266
+ that ruby can easily parse into a Date object, and Ident, being a string that combines
267
+ the service name, version and date.
268
+
269
+ Both these files are not strictly required for Jerbil Services but are expected by some
270
+ jerbil support gems (not yet available).
271
+
272
+ ### JerbilService Parameters
273
+
274
+ The {JerbilService::Base} class expects to receive an options hash containing parameters about
275
+ the service itself and about the logger that the service will set up. This options hash is
276
+ best created using the [Jeckyl gem](https://github.com/osburn-sharp/jeckyl). To make things easier,
277
+ Jerbil provides its own {JerbilService::Config} class that defines the expected parameters and inherits
278
+ the logger parameters from the [Jellog gem](https://github.com/osburn-sharp/jellog). A full description
279
+ of each parameter is available by going to the {JerbilService::Config config class} and following the
280
+ 'See Also' link.
281
+
282
+ The main parameter to consider is :environment, which can be one of :dev, :test and :prod. This allows you to run a
283
+ production quality service across the network, test a ready-to-release upgrade also across
284
+ the network, and develop the next release all in parallel.
285
+
286
+ ### Customising System Methods
287
+
288
+ The {JerbilService::Base} class provides a number of "system" methods that you may want to interact with.
289
+ In general these should not be called directly, which is why they are suffixed with the rather
290
+ cumbersome '_callback'. For example, to verify a service, you should use {JerbilService::Client#verify}
291
+ which calls the appropriate 'verify_callback' method.
292
+
293
+ * verify_callback - this is the method called when, e.g. the 'jerbil' command is asked to verify that
294
+ the service is running. There should be no need to modify this, but if you do you need to pass in
295
+ the service key (see below) because it will be expecting it.
296
+
297
+ * stop_callback - called to stop the service and deals with de-registering and stopping DRb. You may need to
298
+ add other actions before or after these, but be sure to include 'super' in your modified version
299
+
300
+ * wait - this should not be altered and is used when the service is started - ensuring all the DRb calls
301
+ are dealt with in the same scope.
302
+
303
+ ### Keys and PIDs
304
+
305
+ If you start a service using {JerbilService::Supervisor} (or through sbin/jserviced which uses this interface)
306
+ then this will automatically create a private key and save it to the key directory specified in the
307
+ config file (see above). This key is required by all of the above system methods and is deleted when you
308
+ close the service using the same interface (or sbin/jservice-stop).
309
+
310
+ However, when you register the service with Jerbil you get a service key which you can then use as a minor
311
+ security check on clients calling your methods. This is stored as part of the {Jerbil::ServiceRecord}
312
+ object, accessed through the 'key' attribute. Users can access the key when connecting to through
313
+ {JerbilService::Client} using the {JerbilService::Client#service_key} method. There is protected
314
+ method {JerbilService::Base#check_key} which will compare two keys and raise an exception if they
315
+ are not the same (logging the event as well).
316
+
317
+ {JerbilService::Supervisor} will also store the PID of the service when it starts it up, and uses this
318
+ PID if it cannot connect to the service when asking it to stop. Its a blunt instrument but a lot quicker
319
+ than having to do it manually.
320
+
321
+ ## The Client-Server Interface
322
+
323
+ A service can provide a set of methods for clients to use, but how does the client use them? Simple.
324
+ By using the {JerbilService::Client.find_services} method a block will be invoked with a single variable.
325
+ This variable is a "proxy" for the service itself, as well as providing a few extra methods of its own.
326
+ In other words, when you invoke a method on this variable, it checks to see if it is a valid method
327
+ for the real service, and if it is it calls that method with the parameters passed to it.
328
+ DRb takes care of the rest of it.
329
+
330
+ What you need to bear in mind, however, is that the interface between the client and the server is
331
+ always mediated via DRb. This means that variables passed across this interface cannot always be
332
+ treated as if they were local. For example, if you obtain an object from a service and then modify it
333
+ the original object that the service still controls will be unchanged. This is true most
334
+ of the time because Jerbil does not mixin the DRb::DRbUndumped module. However, more
335
+ complex objects may still be passed by reference. For a full discussion of this behaviour
336
+ read the [DRb Overview](http://ruby-doc.org/stdlib-1.8.7/libdoc/drb/rdoc/DRb.html) in
337
+ the standard library.
338
+
339
+ ## Starting Jerbil Services at boot time
340
+
341
+ Its convenient to start a service automatically, and Jerbil tries to make this easy.
342
+ However, what is on offer will probably only work out of the box for Gentoo.
343
+
344
+ There is only one runscript needed and if you followed the installation instructions
345
+ in {file:README.md the readme file} then this will already be installed as /etc/init.d/jserviced.
346
+ To set up a service involves the following:
347
+
348
+ * create a link to /etc/init.d/jserviced for your service, e.g. /etc/init.d/myserviced
349
+ * create a copy of /etc/conf.d/jserviced for your service, e.g. /etc/conf.d/myserviced.
350
+ Ensure these two files have the same name.
351
+ * edit the conf.d file as required.
352
+ * start the service: /etc/init.d/myserviced start
353
+ * add the service to your default runscripts: rc-update add myserviced default
354
+
355
+ The variables defined in the conf.d file are:
356
+
357
+ * NO_DAEMON - set to true to run the service in the foreground, usually to debug it.
358
+ Defaults to false.
359
+ * NO_SYSLOG - suppress messages that would normally be sent to syslog, again usually
360
+ for debug purposes. Defaults to false.
361
+ * CONF_FILE - path to the config file for this service. Defaults to whatever the default
362
+ location is for Jeckyl (e.g. /etc/jermine/myservice.rb)
363
+ * LOG_DAEMON - log the output from the daemon, which covers the startup process before
364
+ the service starts logging itself. By default this will be logged to a file named
365
+ after the service with the suffix _sd added, e.g. /var/log/jermine/myservice_sd.log
366
+ Defaults to false
367
+ * VERBOSE - output more information during the startup process. This does not affect
368
+ the level of logging for the service itself
369
+ * SERVICE_NAME - by default the service name will be determined from the runscript.
370
+ But if, like me, you always seem to want a "d" on the end, then use this to ensure
371
+ the script picks up the right service, e.g. SERVICE_NAME="myservice"
372
+ * SERVICE_USER - by default, the service user will be a user created when Jerbil was
373
+ installed (jermine). Change it here if you want someone else. See below for details.
374
+ * USES - enter any services that this service uses. Make sure each service is on a
375
+ separate line. e.g. 'USES="logger' on one line and 'net"' on the next. See the example
376
+ in /etc/conf.d/jserviced.
377
+ * NEEDS - enter any services that this service needs. Make sure this is at least "jerbild".
378
+ As above, make it one entry per line.
379
+ * DESCRIPTION - a one line description that will be displayed during start/stop operations.
380
+
381
+ All services are super-user'd to a given user for safety within the runscript. By default this is jermine
382
+ but you can set it to another user as above.
383
+
384
+ When setting USES and NEEDS remember that services defined as needed will restart this
385
+ service when they are restarted. Services that are just used do not restart this service
386
+ but will be started before it.
387
+
388
+ ## Errors and Exceptions
389
+
390
+ If you define your parameters using Jeckyl and {JerbilService::Config} and check them
391
+ with the 'jeckyl check' command you have taken the first step to reducing errors with
392
+ you new service. Jerbil tries to keep on going without upsetting its services, so the
393
+ only errors you are likely to suffer are:
394
+
395
+ * {Jerbil::ServiceAlreadyRegistered} if, for example you
396
+ forget to change the environment variable and already have a service running in the
397
+ same environment
398
+ * {Jerbil::MissingServer} if the Jerbil Server is not running. Hopefully
399
+ you will only suffer that one if you have forgotten to start the server!
400
+ * {Jerbil::InvalidService} if you forgot to register your service in /etc/services.
401
+
402
+ All of the other exceptions defined by Jerbil should be rarely encountered. There are
403
+ three main classes if you want to trap errors generically: JerbilError for all exceptions;
404
+ JerbilServiceError for exceptions relating to registering services etc, and JerbilServerError
405
+ for those relating to server opertions.
406
+
407
+
408
+
409
+
410
+