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.
- data/Bugs.rdoc +66 -0
- data/Gemfile +12 -0
- data/History.txt +359 -0
- data/Intro.txt +5 -0
- data/LICENCE.rdoc +159 -0
- data/README.md +335 -0
- data/README_SERVICES.md +410 -0
- data/README_TESTING.md +47 -0
- data/bin/jerbil +62 -0
- data/bin/jerbil-install +56 -0
- data/etc/conf.d/jerbild +15 -0
- data/etc/conf.d/jserviced +39 -0
- data/etc/init.d/jerbild +55 -0
- data/etc/init.d/jserviced +59 -0
- data/etc/jerbil/jerbil-client.rb +2 -0
- data/etc/jerbil/jerbil.rb +83 -0
- data/lib/jerbil.rb +636 -0
- data/lib/jerbil/config.md +49 -0
- data/lib/jerbil/config.rb +67 -0
- data/lib/jerbil/errors.rb +74 -0
- data/lib/jerbil/jerbil_service/base.rb +191 -0
- data/lib/jerbil/jerbil_service/client.rb +325 -0
- data/lib/jerbil/jerbil_service/config.md +119 -0
- data/lib/jerbil/jerbil_service/config.rb +72 -0
- data/lib/jerbil/jerbil_service/sclient.rb +343 -0
- data/lib/jerbil/jerbil_service/support.rb +58 -0
- data/lib/jerbil/jerbil_service/utils.rb +35 -0
- data/lib/jerbil/servers.rb +230 -0
- data/lib/jerbil/service.rb +216 -0
- data/lib/jerbil/support.rb +160 -0
- data/lib/jerbil/thor/server.rb +76 -0
- data/lib/jerbil/thor/service.rb +74 -0
- data/lib/jerbil/version.rb +13 -0
- data/sbin/jerbil-status +120 -0
- data/sbin/jerbil-stop +139 -0
- data/sbin/jerbild +186 -0
- data/sbin/jservice-status +107 -0
- data/sbin/jservice-stop +94 -0
- data/sbin/jserviced +111 -0
- data/spec/jerbil_2_jerbil_spec.rb +87 -0
- data/spec/jerbil_client1_spec.rb +80 -0
- data/spec/jerbil_client_spec.rb +114 -0
- data/spec/jerbil_client_stop_spec.rb +24 -0
- data/spec/jerbil_daemonised/jerbil_local_spec.rb +81 -0
- data/spec/jerbil_daemonised/jerbil_remote_spec.rb +116 -0
- data/spec/jerbil_load.rb +48 -0
- data/spec/jerbil_local_spec.rb +91 -0
- data/spec/jerbil_missing_spec.rb +98 -0
- data/spec/jerbil_remote_spec.rb +117 -0
- data/spec/jerbil_remote_spec_bup.rb +168 -0
- data/spec/jerbil_service_error_spec.rb +56 -0
- data/spec/jerbil_service_spec.rb +41 -0
- data/spec/jerbil_support_spec.rb +69 -0
- data/spec/jservice_utils_spec.rb +38 -0
- data/spec/server_spec.rb +69 -0
- data/spec/server_update_spec.rb +28 -0
- data/spec/service_spec.rb +72 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test_env_spec.rb +53 -0
- data/test/bad_test_service.rb +31 -0
- data/test/conf.d/jerbil +36 -0
- data/test/conf.d/jerbil.conf +39 -0
- data/test/conf.d/jerbil.rb +55 -0
- data/test/conf.d/jerbil_local.rb +33 -0
- data/test/conf.d/jerbil_no_local.conf +39 -0
- data/test/conf.d/jerbil_old.rb +47 -0
- data/test/conf.d/jerbil_test.rb +35 -0
- data/test/conf.d/malformed +1 -0
- data/test/conf.d/missing_services +39 -0
- data/test/conf.d/ruby_test.rb +8 -0
- data/test/init.d/jerbild +14 -0
- data/test/jerbil.rb +51 -0
- data/test/jerbil_config.rb +8 -0
- data/test/jstop.rb +36 -0
- data/test/key.asc +1 -0
- data/test/lib/ruby_test.rb +37 -0
- data/test/lib/ruby_test/config.rb +56 -0
- data/test/lib/ruby_test/version.rb +13 -0
- data/test/pids/jerbil-prod.asc +1 -0
- data/test/pids/jerbil-prod.pid +1 -0
- data/test/pids/jerbil.pid +1 -0
- data/test/private_key_file.asc +3 -0
- data/test/service-stop.rb +86 -0
- data/test/service_mock.rb +94 -0
- data/test/test_service_client.rb +25 -0
- metadata +265 -0
data/README_TESTING.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Jerbil Testing
|
2
|
+
|
3
|
+
Testing is generally through rspec, development/test versions of the Jerbil server, and service mocks.
|
4
|
+
|
5
|
+
## Basic tests
|
6
|
+
|
7
|
+
The following basic rspec tests should be run (all in spec/)
|
8
|
+
|
9
|
+
* jerbil_local_spec - set up a server and register a local service
|
10
|
+
* jerbil_remote_spec - set up a server and register a remote service (as if another server)
|
11
|
+
* jerbil_missing_spec - set up a server, register a remote service (or not) and check if it is missing
|
12
|
+
* server_spec - test the Servers interface using a local server - a local record that assists in connecting
|
13
|
+
to real servers
|
14
|
+
* service_spec - test the Service interface - local records for services known to the server
|
15
|
+
|
16
|
+
The following tests require a jerbil server to be started separately:
|
17
|
+
|
18
|
+
$ export RUBYLIB="lib"
|
19
|
+
$ sbin/jerbild -c test/conf.d/jerbil_test.rb
|
20
|
+
#do the tests
|
21
|
+
$ rspec spec/jerbil_daemonised/jerbil_local_spec.rb
|
22
|
+
$ rspec spec/jerbil_daemonised/jerbil_remote_spec.rb
|
23
|
+
#stop the server
|
24
|
+
$ sbin/jerbil-stop -c test/conf.d/jerbil_test.rb
|
25
|
+
|
26
|
+
The following tests require the RubyTest service to be started as well:
|
27
|
+
|
28
|
+
$ export RUBYLIB="lib:test/lib"
|
29
|
+
$ sbin/jerbild -c test/conf.d/jerbil_test.rb
|
30
|
+
$ sbin/jserviced -c test/conf.d/ruby_test.rb -s ruby_test -V
|
31
|
+
$ rspec spec/jerbil_client_spec.rb
|
32
|
+
$ sbin/jservice-stop -c test/conf.d/ruby_test.rb -s ruby_test -V
|
33
|
+
$ sbin/jerbil-stop -c test/conf.d/jerbil_test.rb
|
34
|
+
|
35
|
+
## Dev and Test servers
|
36
|
+
|
37
|
+
Jerbil can be run with dev and test servers in parallel with any production server. To access these servers from another
|
38
|
+
service requires the :jerbil_env parameter to be set to the required value. This is how the rubytest service operates, so check out
|
39
|
+
the config file above.
|
40
|
+
|
41
|
+
Testing Jerbil across the network is best done using git to clone the jerbil files, and then running the RubyTest tests
|
42
|
+
described above. To check the status of a server, use the jerbil command:
|
43
|
+
|
44
|
+
$ jerbil services -c test/conf.d/jerbil_test.rb
|
45
|
+
$ # and verify
|
46
|
+
$ jerbil services -c test/conf.d/jerbil_test.rb -v
|
47
|
+
|
data/bin/jerbil
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
# = Jerbil command line utility
|
5
|
+
#
|
6
|
+
# == control and display jerbil related info
|
7
|
+
#
|
8
|
+
# Author:: Robert Sharp
|
9
|
+
# Copyright:: Copyright (c) 2011 Robert Sharp
|
10
|
+
# License:: Open Software Licence v3.0
|
11
|
+
#
|
12
|
+
# This software is licensed for use under the Open Software Licence v. 3.0
|
13
|
+
# The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
|
14
|
+
# and in the file copyright.txt. Under the terms of this licence, all derivative works
|
15
|
+
# must themselves be licensed under the Open Software Licence v. 3.0
|
16
|
+
#
|
17
|
+
# Trial using Thor
|
18
|
+
#
|
19
|
+
require 'rubygems'
|
20
|
+
require 'thor'
|
21
|
+
require 'thor/group'
|
22
|
+
require 'jerbil'
|
23
|
+
require 'colored'
|
24
|
+
|
25
|
+
|
26
|
+
require 'jerbil/thor/server'
|
27
|
+
require 'jerbil/thor/service'
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
# the main thor handler
|
32
|
+
class Jerbs < Thor
|
33
|
+
|
34
|
+
#class_option :verbose, :default=>false, :aliases=>'-V', :desc=>'print more information'
|
35
|
+
|
36
|
+
desc "test", "This is just to test things"
|
37
|
+
method_option :debug, :aliases=>'-D', :desc=>'display debug information'
|
38
|
+
def test
|
39
|
+
puts "Hello World"
|
40
|
+
if options[:debug] then
|
41
|
+
puts "Debugging..."
|
42
|
+
puts " Load Path:"
|
43
|
+
$LOAD_PATH.each do |lpath|
|
44
|
+
puts " #{lpath.to_s}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
register Server, :server, "server", "show information about jerbil servers"
|
51
|
+
|
52
|
+
|
53
|
+
register Service, :service, "service", "show information about registered services"
|
54
|
+
|
55
|
+
map "services"=>"service"
|
56
|
+
|
57
|
+
# use separate jeni installer
|
58
|
+
#register Installer, :install, "install", "install jerbil on local machine"
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
Jerbs.start
|
data/bin/jerbil-install
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby18
|
2
|
+
#
|
3
|
+
# @markup ruby
|
4
|
+
# @title Installation Script
|
5
|
+
#
|
6
|
+
# = Jerbil Installation
|
7
|
+
#
|
8
|
+
# == Uses Jeni to install Jerbil Files
|
9
|
+
#
|
10
|
+
# Author:: Robert Sharp
|
11
|
+
# Copyright:: Copyright (c) 2011 Robert Sharp
|
12
|
+
# License:: Open Software Licence v3.0
|
13
|
+
#
|
14
|
+
# This software is licensed for use under the Open Software Licence v. 3.0
|
15
|
+
# The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
|
16
|
+
# and in the file copyright.txt. Under the terms of this licence, all derivative works
|
17
|
+
# must themselves be licensed under the Open Software Licence v. 3.0
|
18
|
+
#
|
19
|
+
#
|
20
|
+
#
|
21
|
+
require 'rubygems' # jeni uses it anyway to find the jerbil gem so why not use it here?
|
22
|
+
require 'jeni'
|
23
|
+
|
24
|
+
|
25
|
+
Jeni::Installer.new_from_gem('jerbil') do |jeni|
|
26
|
+
jeni.optparse(ARGV)
|
27
|
+
jeni.usr # force files to be relative to /usr
|
28
|
+
|
29
|
+
# create a user, if not already created, with its own group
|
30
|
+
jeni.user('jerbil', :skip=>true, :user_group=>true, :home=>'/var/run/jerbil')
|
31
|
+
|
32
|
+
# make the required directories, if they do not already exist
|
33
|
+
jeni.empty_directory('/etc/jerbil')
|
34
|
+
jeni.empty_directory('/var/log/jerbil', :chown=>'jerbil', :chgrp=>'jerbil', :chmod=>0775)
|
35
|
+
jeni.empty_directory('/var/run/jerbil', :chown=>'jerbil', :chgrp=>'jerbil', :chmod=>0775)
|
36
|
+
|
37
|
+
|
38
|
+
jeni.file('etc/jerbil/jerbil.rb', '/etc/jerbil/jerbil.rb', :chown=>'jerbil', :chgrp=>'jerbil', :chmod=>0640)
|
39
|
+
jeni.file('etc/jerbil/jerbil-client.rb', '/etc/jerbil/jerbil-client.rb', :chown=>'jerbil', :chgrp=>'jerbil', :chmod=>0640)
|
40
|
+
|
41
|
+
# configuration file to run the service
|
42
|
+
jeni.file('etc/conf.d/jerbild', '/etc/conf.d/jerbild')
|
43
|
+
# and the init script itself
|
44
|
+
jeni.file('etc/init.d/jerbild', '/etc/init.d/jerbild', :chmod=>0755)
|
45
|
+
# and init files for jservice
|
46
|
+
jeni.file('etc/conf.d/jserviced', '/etc/conf.d/jserviced')
|
47
|
+
jeni.file('etc/init.d/jserviced', '/etc/init.d/jserviced', :chmod=>0755)
|
48
|
+
# the daemon itself, which is executable
|
49
|
+
jeni.wrapper('sbin/jerbild', 'sbin/jerbild', :chmod=>0755)
|
50
|
+
jeni.wrapper('sbin/jerbil-stop', 'sbin/jerbil-stop', :chmod=>0755)
|
51
|
+
jeni.wrapper('sbin/jerbil-status', 'sbin/jerbil-status', :chmod=>0755)
|
52
|
+
jeni.wrapper('sbin/jserviced', 'sbin/jserviced', :chmod=>0755)
|
53
|
+
jeni.wrapper('sbin/jservice-stop', 'sbin/jservice-stop', :chmod=>0755)
|
54
|
+
jeni.wrapper('sbin/jservice-status', 'sbin/jservice-status', :chmod=>0755)
|
55
|
+
|
56
|
+
end.run!
|
data/etc/conf.d/jerbild
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# NO_DAEMON can be set true to prevent the service from daemonizing and run it
|
2
|
+
# in the foreground instead. Only recommended for testing and diagnostics
|
3
|
+
#NO_DAEMON=false
|
4
|
+
|
5
|
+
# NO_SYSLOG can be set true to prevent the logger from logging messages to syslog
|
6
|
+
# Only recommended for testing
|
7
|
+
#NO_SYSLOG=false
|
8
|
+
|
9
|
+
# CONF_FILE can be used to start the service with a configuration from a file
|
10
|
+
# other than the system default (/etc/jerbil/jerbil.rb).
|
11
|
+
#CONF_FILE=
|
12
|
+
|
13
|
+
# By default, the service will suppress all messages to the terminal. For testing and
|
14
|
+
# diagnostics, set VERBOSE to be true and run with NO_DAEMON
|
15
|
+
#VERBOSE=false
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# This file should be used with the jerbil service init script to set
|
2
|
+
# basic options used to start the service. The service itself is configured
|
3
|
+
# by the conf_file and the default setting for this is usually OK
|
4
|
+
|
5
|
+
# NO_DAEMON can be set true to prevent the service from daemonizing and run it
|
6
|
+
# in the foreground instead. Only recommended for testing and diagnostics
|
7
|
+
#NO_DAEMON=false
|
8
|
+
|
9
|
+
# NO_SYSLOG can be set true to prevent the logger from logging messages to syslog
|
10
|
+
# Only recommended for testing
|
11
|
+
#NO_SYSLOG=false
|
12
|
+
|
13
|
+
# CONF_FILE can be used to start the service with a configuration from a file
|
14
|
+
# other than the system default (/etc/jerbil/<service>.rb).
|
15
|
+
#CONF_FILE=
|
16
|
+
|
17
|
+
# LOG_DAEMON can be used to log the output of the daemon to a jellog log file
|
18
|
+
# which is useful for debugging purposes
|
19
|
+
LOG_DAEMON=true
|
20
|
+
|
21
|
+
# By default, the service will suppress all messages to the terminal. For testing and
|
22
|
+
# diagnostics, set VERBOSE to be true and run with NO_DAEMON
|
23
|
+
#VERBOSE=false
|
24
|
+
|
25
|
+
# A service name can be defined here, but in its absence, will be taken from the file name
|
26
|
+
# Which is probably not going to be right if the file has the usual "d" on the end!
|
27
|
+
SERVICE_NAME=""
|
28
|
+
|
29
|
+
# define the user under which this service will run
|
30
|
+
SERVICE_USER=""
|
31
|
+
|
32
|
+
# add any services that this service uses
|
33
|
+
USES="logger
|
34
|
+
net"
|
35
|
+
|
36
|
+
# Add further services that this service needs, remembering the d on the end!
|
37
|
+
NEEDS="jerbild"
|
38
|
+
|
39
|
+
DESCRIPTION="This is a test service for Jerbil!"
|
data/etc/init.d/jerbild
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/sbin/runscript
|
2
|
+
#
|
3
|
+
# INIT Script for the Jerbil - Ruby Object Broker
|
4
|
+
|
5
|
+
|
6
|
+
depend() {
|
7
|
+
use net
|
8
|
+
use logger
|
9
|
+
}
|
10
|
+
|
11
|
+
describe() {
|
12
|
+
einfo "Reliable Broker for Ruby Services"
|
13
|
+
}
|
14
|
+
|
15
|
+
export RUBYOPT="rubygems"
|
16
|
+
export RUBYLIB=""
|
17
|
+
|
18
|
+
# create the options for starting the daemon from the settings in the
|
19
|
+
# /etc/conf.d/jerbild file
|
20
|
+
|
21
|
+
myopts=""
|
22
|
+
[ -n "${NO_DAEMON}" ] && myopts="${myopts} -n"
|
23
|
+
[ -n "${CONF_FILE}" ] && myopts="${myopts} -c ${CONF_FILE}"
|
24
|
+
[ "${VERBOSE}" == "true" ] && [ "${QUIET}" != "true" ] && myopts="${myopts} -V"
|
25
|
+
[ -n "${NO_SYSLOG}" ] && myopts="${myopts} -S"
|
26
|
+
|
27
|
+
|
28
|
+
start() {
|
29
|
+
ebegin "Starting Jerbil Server"
|
30
|
+
|
31
|
+
# /var/run is now temporary and may need to be created at each boot
|
32
|
+
if [ ! -d /var/run/jerbil ] ; then
|
33
|
+
mkdir /var/run/jerbil
|
34
|
+
chown jerbil:jerbil /var/run/jerbil
|
35
|
+
einfo "Created /var/run/jerbil"
|
36
|
+
fi
|
37
|
+
|
38
|
+
/bin/su -c "/usr/sbin/jerbild ${myopts}" - jerbil
|
39
|
+
|
40
|
+
eend $?
|
41
|
+
}
|
42
|
+
|
43
|
+
status() {
|
44
|
+
ebegin "Checking Jerbil Status"
|
45
|
+
/usr/sbin/jerbil-status ${myopts}
|
46
|
+
eend $?
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
stop() {
|
51
|
+
ebegin "Stopping Jerbil Server"
|
52
|
+
/usr/sbin/jerbil-stop ${myopts}
|
53
|
+
eend $?
|
54
|
+
}
|
55
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/sbin/runscript
|
2
|
+
#
|
3
|
+
# INIT Script for a Jerbil Service
|
4
|
+
|
5
|
+
# create dependencies from the list of services in $NEEDS and $USES
|
6
|
+
depend() {
|
7
|
+
for need_service in $NEEDS
|
8
|
+
do
|
9
|
+
need $need_service
|
10
|
+
done
|
11
|
+
for use_service in $USES
|
12
|
+
do
|
13
|
+
use $use_service
|
14
|
+
done
|
15
|
+
}
|
16
|
+
|
17
|
+
# make sure there are no unexpected rubylibs
|
18
|
+
export RUBYLIB=""
|
19
|
+
export RUBYOPT="rubygems"
|
20
|
+
|
21
|
+
myopts=""
|
22
|
+
[ -n "${NO_DAEMON}" ] && myopts="${myopts} -n"
|
23
|
+
[ -n "${CONF_FILE}" ] && myopts="${myopts} -c ${CONF_FILE}"
|
24
|
+
[ "${VERBOSE}" == "true" ] && [ "${QUIET}" != "true" ] && myopts="${myopts} -V"
|
25
|
+
[ -n "${NO_SYSLOG}" ] && myopts="${myopts} -S"
|
26
|
+
[ -n "${LOG_DAEMON}" ] && myopts="${myopts} -l"
|
27
|
+
[ "$SERVICE_NAME" == "" ] && SERVICE_NAME="${SVCNAME}"
|
28
|
+
[ "$SERVICE_USER" == "" ] && SERVICE_USER="jerbil"
|
29
|
+
|
30
|
+
start() {
|
31
|
+
ebegin "Starting Jerbil Service ${SERVICE_NAME}"
|
32
|
+
|
33
|
+
|
34
|
+
# create the options for starting the daemon from the settings in the
|
35
|
+
# /etc/conf.d/jservice file (same name as this link)
|
36
|
+
|
37
|
+
/bin/su -c "/usr/sbin/jserviced ${myopts} -s ${SERVICE_NAME}" - ${SERVICE_USER}
|
38
|
+
|
39
|
+
eend $?
|
40
|
+
}
|
41
|
+
|
42
|
+
status() {
|
43
|
+
ebegin "Checking status for Jerbil Service ${SERVICE_NAME}"
|
44
|
+
/usr/sbin/jservice-status ${myopts} -s ${SERVICE_NAME}
|
45
|
+
eend $?
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
stop() {
|
50
|
+
ebegin "Stopping Jerbil Service ${SERVICE_NAME}"
|
51
|
+
/usr/sbin/jservice-stop ${myopts} -s ${SERVICE_NAME}
|
52
|
+
eend $?
|
53
|
+
}
|
54
|
+
|
55
|
+
describe() {
|
56
|
+
einfo ${DESCRIPTION}
|
57
|
+
|
58
|
+
}
|
59
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
#
|
2
|
+
# Configuration Options for: Jelly::Options
|
3
|
+
#
|
4
|
+
|
5
|
+
# Number of log files to retain at any time, between 0 and 20
|
6
|
+
#log_rotation 2
|
7
|
+
|
8
|
+
# Location for Jelly (logging utility) to save log files
|
9
|
+
#log_dir "/var/log/jerbil"
|
10
|
+
|
11
|
+
# Set the string to be used for marking the log with logger.mark
|
12
|
+
#log_mark " ===== Mark ====="
|
13
|
+
|
14
|
+
# Reset the logfile when starting logging by setting to true, otherwise append to
|
15
|
+
# existing log
|
16
|
+
#log_reset false
|
17
|
+
|
18
|
+
# Setting to true (the default) will flush log messages immediately, which is useful if you
|
19
|
+
# need to monitor logs dynamically
|
20
|
+
#log_sync true
|
21
|
+
|
22
|
+
# Size of a log file (in MB) before switching to the next log, upto 20 MB
|
23
|
+
#log_length 1
|
24
|
+
|
25
|
+
# Format string for time stamps. Needs to be a string that is recognised by String.strftime
|
26
|
+
# Any characters not recognised by strftime will be printed verbatim, which may not be what you want
|
27
|
+
#log_date_time_format "%Y-%m-%d %H:%M:%S"
|
28
|
+
|
29
|
+
# Controls the amount of logging done by Jelly
|
30
|
+
#
|
31
|
+
# * :system - standard message, plus log to syslog
|
32
|
+
# * :verbose - more generous logging to help resolve problems
|
33
|
+
# * :debug - usually used only for resolving problems during development
|
34
|
+
#
|
35
|
+
#log_level :system
|
36
|
+
|
37
|
+
# Set to false to suppress colourful logging. Default colours can be changed by calling
|
38
|
+
# colours= method
|
39
|
+
#log_coloured true
|
40
|
+
|
41
|
+
#
|
42
|
+
# Configuration Options for: JerbilService::Config
|
43
|
+
#
|
44
|
+
|
45
|
+
# private key dir used to authenticate privileged users
|
46
|
+
#key_dir "/var/run/jerbil"
|
47
|
+
|
48
|
+
# Set the default environment for service commands etc.
|
49
|
+
#
|
50
|
+
# Can be one of :prod, :test, :dev
|
51
|
+
#environment :prod
|
52
|
+
|
53
|
+
# Set this only to use a Jerbil Server that is not running in the production environment
|
54
|
+
#jerbil_env
|
55
|
+
|
56
|
+
# directory used to store the daemons pid to assist in stopping reluctant servers
|
57
|
+
#pid_dir "/var/run/jerbil"
|
58
|
+
|
59
|
+
#
|
60
|
+
# Configuration Options for: Jerbil::Config
|
61
|
+
#
|
62
|
+
|
63
|
+
# A secret key available to all Jerbil Servers and used to authenticate the initial registration.
|
64
|
+
# If security is an issue, ensure that this config file is readable only be trusted users
|
65
|
+
secret "hK78l/z1mIDBOs+/Qx2q7k5beExChmdc3tpw81qTBNLmcQknRrY93oHzIAd3DNo2"
|
66
|
+
|
67
|
+
# A valid netmask for the hosts to search using the above net address. This should be
|
68
|
+
# between 24 (a class C network) and 30, beyound which its not much of a network. If you only have a few
|
69
|
+
# hosts it will be easier to restrict them to a small subnet.
|
70
|
+
#
|
71
|
+
# To find out more about netmasks, go to [UnixWiz](http://www.unixwiz.net/techtips/netmask-ref.html).
|
72
|
+
#net_mask 26
|
73
|
+
|
74
|
+
# Provide a timeout when searching for jerbil servers on the net during startup.
|
75
|
+
# Depending on the size of the net mask this timeout may make the search long.
|
76
|
+
# The default should work in most cases
|
77
|
+
#scan_timeout 0.1
|
78
|
+
|
79
|
+
# A valid IPv4 address for the LAN on which the servers will operate.
|
80
|
+
# Note that the broker uses this address to search for all servers.
|
81
|
+
# Therefore a large range will take a long time to search. Set the net_mask to limit this.
|
82
|
+
#net_address "192.168.0.1"
|
83
|
+
|
data/lib/jerbil.rb
ADDED
@@ -0,0 +1,636 @@
|
|
1
|
+
#
|
2
|
+
# = JERBIL
|
3
|
+
#
|
4
|
+
# == Jumpin' Ermin's Ruby Broker for Integrated Linux services!
|
5
|
+
#
|
6
|
+
# Author:: Robert Sharp
|
7
|
+
# Copyright:: Copyright (c) 2010 Robert Sharp
|
8
|
+
# License:: Open Software Licence v3.0
|
9
|
+
#
|
10
|
+
# This software is licensed for use under the Open Software Licence v. 3.0
|
11
|
+
# The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
|
12
|
+
# and in the file copyright.txt. Under the terms of this licence, all derivative works
|
13
|
+
# must themselves be licensed under the Open Software Licence v. 3.0
|
14
|
+
#
|
15
|
+
# A reliable (hopefully) object request broker for ruby services.
|
16
|
+
#
|
17
|
+
# A server runs on every machine. Servers register with Jerbil and offer a polling method so that
|
18
|
+
# Jerbil can keep checking they are alive. Servers that want to take network wide clients are
|
19
|
+
# relayed to all the other Jerbil servers.
|
20
|
+
#
|
21
|
+
# Clients ask for a service and receive the name and port to connect through using DRb.
|
22
|
+
#
|
23
|
+
# Jerbil is meant to be used behind a higher level wrapper that hides DRb as well
|
24
|
+
#
|
25
|
+
#
|
26
|
+
require 'rubygems'
|
27
|
+
require 'drb'
|
28
|
+
require 'socket'
|
29
|
+
require 'jellog'
|
30
|
+
require 'jerbil/errors'
|
31
|
+
require 'jerbil/service'
|
32
|
+
require 'jerbil/servers'
|
33
|
+
require 'jerbil/version'
|
34
|
+
require 'jerbil/support'
|
35
|
+
|
36
|
+
# == JERBIL - Jumpin' Ermin's Ruby Broker for Integrated Linux services!
|
37
|
+
#
|
38
|
+
# A network server for registering services and a suite of classes and methods to
|
39
|
+
# manage these services and to connect with them.
|
40
|
+
#
|
41
|
+
module Jerbil
|
42
|
+
|
43
|
+
# The Broker, being a server class that runs on each machine on which Jerbil services will run or will be
|
44
|
+
# required. The Broker registers services and interacts with other servers to share information
|
45
|
+
# about services across the network.
|
46
|
+
#
|
47
|
+
# It is not necessary to use this interface directly. By using the {JerbilService::Base}
|
48
|
+
# class all interaction with the server is done under the hood. See {file:README_SERVICES.md Services Readme}
|
49
|
+
# for more details.
|
50
|
+
#
|
51
|
+
# Key methods are:
|
52
|
+
#
|
53
|
+
# * *{Jerbil::Broker#register}* to add a service to the broker's database
|
54
|
+
# * **{Jerbil::Broker#remove}** to remove a service from the broker's database
|
55
|
+
# * **{#find} to obtain information about one or more services matching given criteria
|
56
|
+
#
|
57
|
+
# Methods used between servers are:
|
58
|
+
#
|
59
|
+
# * {Jerbil::Broker#register_server} to add a remote server to the broker's database
|
60
|
+
# * {Jerbil::Broker#detach_server} to remove a remote server from the broker's database
|
61
|
+
# * {Jerbil::Broker#get_local_services} called by a remote server to get all of the
|
62
|
+
# local services known to this server
|
63
|
+
# * {Jerbil::Broker#register_remote} for a remote server to register a new service
|
64
|
+
# * {Jerbil::Broker#remove_remote} for a remote server to remove a service
|
65
|
+
#
|
66
|
+
# Methods used to internally:
|
67
|
+
#
|
68
|
+
# * {Jerbil::Broker#stop} to stop the server gracefully
|
69
|
+
# * {Jerbil::Broker#missing_service?} to check if a service is missing and remove it from
|
70
|
+
# the database if it is
|
71
|
+
#
|
72
|
+
class Broker
|
73
|
+
|
74
|
+
# create a new Jerbil server
|
75
|
+
#
|
76
|
+
# The options for the server are defined in {Jerbil::Config} and are best created
|
77
|
+
# using this class. This is a [Jeckyl](https://github.com/osburn-sharp/jeckyl) config file.
|
78
|
+
# Further details are provided in the {file:README.md Readme file}.
|
79
|
+
#
|
80
|
+
# The private key should be unique to this server and is used to authenticate system actions
|
81
|
+
# and to authenticate remote servers. Its not very secure so more a way of avoiding mistakes.
|
82
|
+
# The key is best created using {Jerbil::Support.create_private_key}.
|
83
|
+
#
|
84
|
+
# @param [Hash] options a hash of various options as defined in {Jerbil::Config}.
|
85
|
+
# @param [String] pkey a private key generated by the script calling the broker and used
|
86
|
+
# to authenticate system calls
|
87
|
+
def initialize(options, pkey) #log_dir, log_level=:system)
|
88
|
+
|
89
|
+
# store details of this server and remote servers
|
90
|
+
@env = options[:environment] || :prod
|
91
|
+
@private_key = pkey
|
92
|
+
@secret = options[:secret]
|
93
|
+
|
94
|
+
@local = Jerbil::Servers.create_local_server(@env, @private_key)
|
95
|
+
@remote_servers = Array.new
|
96
|
+
|
97
|
+
|
98
|
+
# who am i
|
99
|
+
#@host = Socket.gethostname
|
100
|
+
|
101
|
+
#store local and remote services
|
102
|
+
@store = Array.new
|
103
|
+
@remote_store = Array.new
|
104
|
+
|
105
|
+
# create a jellog logger that continues any previous log and keeps the last 5 log files
|
106
|
+
app_name = "Jerbil-#{options[:environment].to_s}"
|
107
|
+
log_opts = Jellog::Logger.get_options(options)
|
108
|
+
@logger = Jellog::Logger.new(app_name, log_opts)
|
109
|
+
@logger.mark
|
110
|
+
@logger.debug "Started the Logger for Jerbil"
|
111
|
+
|
112
|
+
|
113
|
+
# some statistical data
|
114
|
+
@started = Time.now
|
115
|
+
@registrations = 0
|
116
|
+
@logger.verbose("Searching for remote servers")
|
117
|
+
network_servers = Jerbil::Servers.find_servers(@env, options[:net_address], options[:net_mask], options[:scan_timeout])
|
118
|
+
@logger.verbose("Found #{@remote_servers.length} remote servers")
|
119
|
+
|
120
|
+
# now loop round the remote servers to see if any are there
|
121
|
+
network_servers.each do |remote_server|
|
122
|
+
rjerbil = remote_server.connect
|
123
|
+
unless rjerbil.nil?
|
124
|
+
@logger.debug "Getting Remote Services. Connecting to : #{remote_server.inspect}"
|
125
|
+
# there is a remote server, so tell it about me
|
126
|
+
begin
|
127
|
+
rkey = rjerbil.register_server(@local, @secret, @env)
|
128
|
+
remote_server.set_key(rkey)
|
129
|
+
@logger.debug "Key for #{remote_server.fqdn}: #{rkey}"
|
130
|
+
rjerbil.get_local_services(rkey).each {|ls| add_service_to_store(@remote_store, ls)}
|
131
|
+
# add it to the list of verified servers
|
132
|
+
@remote_servers << remote_server
|
133
|
+
rescue DRb::DRbConnError
|
134
|
+
# assume it is not working
|
135
|
+
@logger.verbose("Failed to get remote services from server: #{remote_server.fqdn}")
|
136
|
+
rescue JerbilAuthenticationError => jerr
|
137
|
+
@logger.warn("Remote server authentication failed, skipping")
|
138
|
+
@logger.warn(" #{jerr.message}")
|
139
|
+
rescue ArgumentError, NoMethodError
|
140
|
+
@logger.warn("Remote server incompatibility, skipping")
|
141
|
+
rescue => jerr
|
142
|
+
@logger.exception(jerr)
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
@logger.system("Started up the Jerbil Server")
|
149
|
+
|
150
|
+
@logger.debug "My key: #{@private_key}"
|
151
|
+
@logger.debug "Stored remote keys:"
|
152
|
+
@remote_servers.each do |rs|
|
153
|
+
@logger.debug " #{rs.fqdn}: #{rs.key}"
|
154
|
+
end
|
155
|
+
|
156
|
+
rescue => jerr
|
157
|
+
@logger.exception(jerr)
|
158
|
+
raise
|
159
|
+
end
|
160
|
+
|
161
|
+
# date/time at which the server was started
|
162
|
+
attr_reader :started
|
163
|
+
|
164
|
+
# the number of registrations since the server started
|
165
|
+
attr_reader :registrations
|
166
|
+
|
167
|
+
# the remote servers at any one time
|
168
|
+
#
|
169
|
+
# @return [Array] of {Jerbil::Servers}
|
170
|
+
attr_reader :remote_servers
|
171
|
+
|
172
|
+
# The current version of the Jerbil Server
|
173
|
+
# @return [String] version number in the form N.N.N
|
174
|
+
def version
|
175
|
+
Jerbil::Version
|
176
|
+
end
|
177
|
+
|
178
|
+
# the total number of services currently registered with the server
|
179
|
+
# @return [Numeric] count of services
|
180
|
+
def service_count
|
181
|
+
@store.length + @remote_store.length
|
182
|
+
end
|
183
|
+
|
184
|
+
# the number of local services registered with the server
|
185
|
+
# @return [Numeric] count of services
|
186
|
+
def local_service_count
|
187
|
+
@store.length
|
188
|
+
end
|
189
|
+
|
190
|
+
# the number of remote services registered with the server
|
191
|
+
# @return [Numeric] count of services
|
192
|
+
def remote_service_count
|
193
|
+
@remote_store.length
|
194
|
+
end
|
195
|
+
|
196
|
+
# register a service to the local server
|
197
|
+
#
|
198
|
+
# The caller registers the given service. The server will check that the
|
199
|
+
# service is not already registered before adding it. It will then
|
200
|
+
# inform all the other servers it is aware of about this service so that
|
201
|
+
# anyone on the network can reach it. See {Jerbil::Broker#register_remote} to
|
202
|
+
# see what happens when this methods registers a service with a remote server.
|
203
|
+
#
|
204
|
+
# @param [Jerbil::ServiceRecord] service representing the
|
205
|
+
# service being registered
|
206
|
+
# @raise [ServiceAlreadyRegistered] if the service is already registered
|
207
|
+
# @raise [ServiceNotLocal] if someone should attempt to register a service
|
208
|
+
# that is not local to this server
|
209
|
+
#
|
210
|
+
def register(service)
|
211
|
+
@logger.verbose("About to register a local service: #{service.ident}")
|
212
|
+
if service.local? then
|
213
|
+
service.register
|
214
|
+
add_service_to_store(@store, service)
|
215
|
+
@registrations += 1
|
216
|
+
@logger.system("Registered Local Service: #{service.ident}")
|
217
|
+
|
218
|
+
@remote_servers.each do |rserver|
|
219
|
+
rjerbil = rserver.connect
|
220
|
+
unless rjerbil.nil?
|
221
|
+
@logger.debug("Registering remote. Connected to #{rserver.fqdn}")
|
222
|
+
begin
|
223
|
+
rjerbil.register_remote(rserver.key, service)
|
224
|
+
@logger.verbose("Registered Service: #{service.name} on server: #{rserver.fqdn}")
|
225
|
+
rescue DRb::DRbConnError
|
226
|
+
# assume it is not working
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
else
|
231
|
+
# someone is attempting to register a service that is not local
|
232
|
+
@logger.warn("Attempt to register non-local service: #{service.ident}")
|
233
|
+
raise ServiceNotLocal
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# remove a service from the register
|
238
|
+
#
|
239
|
+
# does nothing if the service is not registered, otherwise removes it
|
240
|
+
# locally and then calls {Jerbil::Broker#remove_remote} for each
|
241
|
+
# registered server.
|
242
|
+
#
|
243
|
+
# @param [Jerbil::ServiceRecord] service to remove
|
244
|
+
def remove(service)
|
245
|
+
if @store.include?(service) then
|
246
|
+
# its a local one
|
247
|
+
@store.delete(service)
|
248
|
+
@logger.system("Deleted Service: #{service.ident}")
|
249
|
+
else
|
250
|
+
@logger.warn("Attempt was made to remove a service that is not registered: #{service.ident}")
|
251
|
+
@logger.warn("Trying to remove it remotely anyway")
|
252
|
+
end
|
253
|
+
@remote_servers.each do |rserver|
|
254
|
+
rjerbil = rserver.connect
|
255
|
+
unless rjerbil.nil?
|
256
|
+
@logger.debug("Connected to #{rserver.fqdn}")
|
257
|
+
begin
|
258
|
+
rjerbil.remove_remote(rserver.key, service)
|
259
|
+
@logger.verbose("Removed Service from remote server: #{service.ident}")
|
260
|
+
rescue DRb::DRbConnError
|
261
|
+
# assume it is not working
|
262
|
+
@logger.debug("Skipping over remove_remote for #{rserver.fqdn} while removing #{service.ident}")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
# return the services that match the given criteria
|
269
|
+
#
|
270
|
+
# search for services based on name, environment etc:
|
271
|
+
#
|
272
|
+
# broker.find(:name=>'MyService', :env=>:test)
|
273
|
+
#
|
274
|
+
# If an option is not specified it will be ignored. Find uses {Jerbil::ServiceRecord#matches?}
|
275
|
+
# to compare services to the given criteria.
|
276
|
+
#
|
277
|
+
# Normally this method will log the access to each service found (keeps a count)
|
278
|
+
# This can be disabled by setting :ignore_access to true. This is used internally
|
279
|
+
# to avoid counting Jerbil operations as service accesses.
|
280
|
+
#
|
281
|
+
# There are also various short-cut methods that can be used:
|
282
|
+
# {Jerbil::Broker#get get}, {Jerbil::Broker#get_local get_local} and {Jerbil::Broker#get_all get_all}
|
283
|
+
#
|
284
|
+
# @param [Hash] args search arguments
|
285
|
+
# @option args [String] :name to match exactly the name of the service
|
286
|
+
# @option args [Symbol] :env to match the services environment (:dev, :test, :prod)
|
287
|
+
# @option args [String] :host to match exactly the name of the host on
|
288
|
+
# which the service is running
|
289
|
+
# @option args [String] :key to match exactly the service key
|
290
|
+
# @option args [Boolean] :ignore_access do not count this call as an access
|
291
|
+
# @return [Array] {Jerbil::ServiceRecord Services} that match or nil if none
|
292
|
+
def find(args={})
|
293
|
+
#options = {:name=>nil, :port=>nil, :env=>nil}.merge(args)
|
294
|
+
results = Array.new
|
295
|
+
services = @store + @remote_store
|
296
|
+
services.each do |service|
|
297
|
+
if service.matches?(args) then
|
298
|
+
service.log_access unless args[:ignore_access]
|
299
|
+
results << service
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
@logger.verbose("Searching for services. Found #{results.length} matching.")
|
304
|
+
@logger.verbose(" Arguments: #{args.inspect}")
|
305
|
+
|
306
|
+
return results
|
307
|
+
end
|
308
|
+
|
309
|
+
# get the first service that matches the given criteria.
|
310
|
+
#
|
311
|
+
# Uses {Jerbil::Broker#find} to do the real work and returns the first service.
|
312
|
+
# There is no guarantee of the order. In addition,
|
313
|
+
# unless :ignore_acess is true, this call will check if the service
|
314
|
+
# is connected, and will return nil if it is not
|
315
|
+
#
|
316
|
+
# @param (see #find)
|
317
|
+
# @option (see #find)
|
318
|
+
# @return (see #find)
|
319
|
+
def get(args={})
|
320
|
+
results = Array.new
|
321
|
+
results = self.find(args)
|
322
|
+
if results.length >= 1 then
|
323
|
+
service = results[0]
|
324
|
+
@logger.verbose("Get returned #{service.ident}")
|
325
|
+
unless args[:ignore_access]
|
326
|
+
# check if it is working
|
327
|
+
begin
|
328
|
+
service.connect
|
329
|
+
rescue ServiceCallbackMissing
|
330
|
+
@logger.warning("Verifying #{service.ident} failed due to missing callback")
|
331
|
+
# missing callback but still return it...
|
332
|
+
rescue ServiceConnectError
|
333
|
+
@logger.verbose("Verification failed for #{service.ident}")
|
334
|
+
return nil
|
335
|
+
end
|
336
|
+
end
|
337
|
+
return service
|
338
|
+
else
|
339
|
+
return nil
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
# get the first service that matches the given criteria and is running on the same
|
344
|
+
# processor
|
345
|
+
#
|
346
|
+
# @param (see #find)
|
347
|
+
# @option (see #find)
|
348
|
+
# @return (see #find)
|
349
|
+
def get_local(args={})
|
350
|
+
new_args = args.merge({:host=>@host})
|
351
|
+
return get(new_args)
|
352
|
+
end
|
353
|
+
|
354
|
+
# return all services
|
355
|
+
#
|
356
|
+
# does not require any matching criteria.
|
357
|
+
#
|
358
|
+
# @param [Boolean] ignore_access is the same as :ignore_access for #find
|
359
|
+
# @return (see #find)
|
360
|
+
def get_all(ignore_access=false)
|
361
|
+
self.find(:ignore_access => ignore_access)
|
362
|
+
end
|
363
|
+
|
364
|
+
# Checks for a potentially missing service and removes it if it cannot be found.
|
365
|
+
#
|
366
|
+
# What to do if you cannot connect to a service that Jerbil thinks is there?
|
367
|
+
# check if its local, try to connect and if OK then return false to allow retries
|
368
|
+
# otherwise remove the service and return true.
|
369
|
+
#
|
370
|
+
# If the service is not local, find its server and ask it the same question.
|
371
|
+
# if the server is not there, then fake being that server and remove_remote from
|
372
|
+
# everyone. Don't forget to remove it from here too!
|
373
|
+
#
|
374
|
+
# @param [Jerbil::ServiceRecord] service to check for
|
375
|
+
# @return [Boolean] true if service was missing
|
376
|
+
def service_missing?(service)
|
377
|
+
# is it one of mine?
|
378
|
+
if service.local? then
|
379
|
+
#yes
|
380
|
+
@logger.verbose("Local service missing for #{service.ident}?")
|
381
|
+
begin
|
382
|
+
service.connect
|
383
|
+
# seems to be fine
|
384
|
+
@logger.info("Missing service was found to be OK: #{service.ident}")
|
385
|
+
return false
|
386
|
+
rescue
|
387
|
+
# failed to connect for some reason.
|
388
|
+
# trying to stop the service
|
389
|
+
@logger.debug("Local service appears to be missing: #{service.ident}")
|
390
|
+
# and now remove it from the record
|
391
|
+
self.remove(service)
|
392
|
+
@logger.system("Removed missing local service: #{service.ident}")
|
393
|
+
return true
|
394
|
+
end
|
395
|
+
else
|
396
|
+
# not one of mine, so who owns it
|
397
|
+
@logger.verbose("Missing service is not local: #{service.ident}")
|
398
|
+
failed_remote_server = nil
|
399
|
+
@remote_servers.each do |rserver|
|
400
|
+
if rserver.fqdn == service.host then
|
401
|
+
# found it, so try to warn it
|
402
|
+
@logger.debug("Service: #{service.ident} belongs to #{rserver.fqdn}")
|
403
|
+
begin
|
404
|
+
rjerbil = rserver.connect
|
405
|
+
return rjerbil.service_missing?(service)
|
406
|
+
rescue
|
407
|
+
# whoops, failed to connect to remote server
|
408
|
+
# so assume it has gone and allow method to continue
|
409
|
+
# so that it removes the service as if it was the remote server
|
410
|
+
failed_remote_server = rserver
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
# only got here because could not connect to the server
|
415
|
+
unless failed_remote_server.nil?
|
416
|
+
@logger.warn("Failed to connect to server: #{failed_remote_server.fqdn}, removing service for it")
|
417
|
+
rkey = failed_remote_server.key
|
418
|
+
self.remove_remote(rkey, service)
|
419
|
+
@remote_servers.each do |rserver|
|
420
|
+
begin
|
421
|
+
rjerbil = rserver.connect
|
422
|
+
rjerbil.remove_remote(rkey, service)
|
423
|
+
@logger.debug("Removed service: #{service.ident} from server #{rserver.fqdn}")
|
424
|
+
rescue
|
425
|
+
# server not up, so ignore
|
426
|
+
@logger.debug("Failed to connect to server to remove service: #{rserver.fqdn}, but who cares!")
|
427
|
+
end
|
428
|
+
end
|
429
|
+
return true
|
430
|
+
else
|
431
|
+
# strange? Should not have a service for which there is no server...
|
432
|
+
@logger.warn("Could not find a server for #{service.ident}. How could this happen?")
|
433
|
+
return false
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
# close the logger that Jerbil is using
|
439
|
+
#
|
440
|
+
# probably only useful for testing?
|
441
|
+
def close
|
442
|
+
@logger.close
|
443
|
+
end
|
444
|
+
|
445
|
+
# simple method to check that the server is running from a remote client
|
446
|
+
def verify
|
447
|
+
return true
|
448
|
+
end
|
449
|
+
|
450
|
+
|
451
|
+
# stop the Jerbil server
|
452
|
+
#
|
453
|
+
# Need to make sure the caller knows what they are doing so requires the
|
454
|
+
# server's private key.
|
455
|
+
#
|
456
|
+
# @param [String] private_key - as given to the server at start-up.
|
457
|
+
def stop(private_key)
|
458
|
+
if @private_key == private_key then
|
459
|
+
@logger.info("About to stop the Jerbil Server")
|
460
|
+
@remote_servers.each do |rserver|
|
461
|
+
begin
|
462
|
+
rjerbil = rserver.connect
|
463
|
+
@logger.verbose("Closing connection to; #{rserver.ident}")
|
464
|
+
rjerbil.detach_server(rserver.key, @local)
|
465
|
+
rescue ServerConnectError, DRb::DRbConnError
|
466
|
+
@logger.error("Failed to connect to #{rserver.ident}")
|
467
|
+
end
|
468
|
+
end
|
469
|
+
@logger.system("Stopping the Jerbil Server now")
|
470
|
+
@logger.close
|
471
|
+
DRb.stop_service
|
472
|
+
#exit!
|
473
|
+
else
|
474
|
+
@logger.system("Stop called with incorrect private key")
|
475
|
+
@logger.debug(" Private Key provided:")
|
476
|
+
@logger.debug("#{private_key}")
|
477
|
+
@logger.debug(" Private Key required")
|
478
|
+
@logger.debug("#{@private_key}")
|
479
|
+
raise InvalidPrivateKey
|
480
|
+
end
|
481
|
+
rescue ServerConnectError
|
482
|
+
@logger.error("Connection to remote server failed")
|
483
|
+
rescue InvalidPrivateKey
|
484
|
+
raise
|
485
|
+
rescue => err
|
486
|
+
@logger.exception(err)
|
487
|
+
end
|
488
|
+
|
489
|
+
#================================================
|
490
|
+
#
|
491
|
+
# SERVER related methods
|
492
|
+
#
|
493
|
+
#================================================
|
494
|
+
|
495
|
+
|
496
|
+
# Register a remote server, providing limited authentication.
|
497
|
+
#
|
498
|
+
# Registering a server
|
499
|
+
# will purge any old server record and any old services for that server
|
500
|
+
#
|
501
|
+
# @param [Servers] server - the remote server's Servers record
|
502
|
+
# @param [String] secret shared between all servers on the net
|
503
|
+
# @param [Symbol] env of the calling server, just to ensure it is the same
|
504
|
+
# @return [String] private key of the called server to be used for further interactions
|
505
|
+
# @raise [JerbilAuthenticationError] if the server fails to authenticate
|
506
|
+
#
|
507
|
+
def register_server(server, secret, env)
|
508
|
+
@logger.debug("Attempting to register server: #{server.ident}")
|
509
|
+
unless secret == @secret
|
510
|
+
@logger.debug "mismatching secret: #{secret}"
|
511
|
+
raise JerbilAuthenticationError, @logger.error("Secret key from #{server.fqdn} does not match")
|
512
|
+
end
|
513
|
+
unless env = @env
|
514
|
+
raise JerbilAuthenticationError, @logger.error("Registering server with #{env}, against #{@env}")
|
515
|
+
end
|
516
|
+
# need to delete any stale existing record
|
517
|
+
@remote_servers.delete_if {|rserver| rserver.fqdn == server.fqdn}
|
518
|
+
|
519
|
+
# registering this new server, but there may be stale services as well
|
520
|
+
@remote_store.delete_if {|rservice| rservice.host == server.fqdn}
|
521
|
+
|
522
|
+
@remote_servers << server
|
523
|
+
@logger.debug "Registered a new server"
|
524
|
+
@logger.debug " #{server.ident}: #{server.key}"
|
525
|
+
|
526
|
+
return @private_key
|
527
|
+
end
|
528
|
+
|
529
|
+
# get all of the local services registered with this server
|
530
|
+
#
|
531
|
+
# @param [String] my_key must be the called servers private key shared
|
532
|
+
# with a remote server through {Jerbil::Broker#register_server}.
|
533
|
+
# @raise [InvalidServerKey] is the given key is incorrect
|
534
|
+
# @return [Array] of {ServiceRecord}
|
535
|
+
#
|
536
|
+
def get_local_services(my_key)
|
537
|
+
raise InvalidServerKey, @logger.error("get_local_services: incorrect key: #{my_key}") unless @private_key == my_key
|
538
|
+
return @store.dup
|
539
|
+
end
|
540
|
+
|
541
|
+
|
542
|
+
# register a remote service
|
543
|
+
#
|
544
|
+
# This is called by a jerbil service when it wants to register a service local to
|
545
|
+
# it with all the other servers. This will siltenly delete any existing service record.
|
546
|
+
#
|
547
|
+
# @param [String] my_key - the caller must provide this server's private key
|
548
|
+
# @param [Service] service - the service to be registered
|
549
|
+
# @raise ServiceAlreadyRegistered if the service is a duplicate
|
550
|
+
#
|
551
|
+
def register_remote(my_key, service)
|
552
|
+
@logger.debug "About to register a remote service:"
|
553
|
+
@logger.debug " #{service.inspect}"
|
554
|
+
|
555
|
+
unless @private_key == my_key
|
556
|
+
@logger.warn("register remote: incorrect key: #{my_key}, ignoring")
|
557
|
+
return true
|
558
|
+
end
|
559
|
+
|
560
|
+
# perhaps there is a stale record for this service? Stops add below from assuming it is missing etc
|
561
|
+
@remote_store.delete_if {|rservice| rservice.same_service?(service)}
|
562
|
+
|
563
|
+
add_service_to_store(@remote_store, service)
|
564
|
+
@logger.info("Registered Remote Service: #{service.ident}")
|
565
|
+
return true
|
566
|
+
|
567
|
+
end
|
568
|
+
|
569
|
+
# delete a remote service from this server
|
570
|
+
#
|
571
|
+
# @param (see register_remote)
|
572
|
+
def remove_remote(my_key, service)
|
573
|
+
@logger.debug "About to remove a remote service:"
|
574
|
+
@logger.debug " #{service.inspect}"
|
575
|
+
|
576
|
+
unless @private_key == my_key
|
577
|
+
@logger.warn("remove_remote: incorrect key: #{my_key}")
|
578
|
+
return true
|
579
|
+
end
|
580
|
+
@remote_store.delete_if {|s| s == service}
|
581
|
+
@logger.info("Deleted Remote Service: #{service.ident}")
|
582
|
+
return true
|
583
|
+
end
|
584
|
+
|
585
|
+
# detach a remote server from this server
|
586
|
+
#
|
587
|
+
# called when the remote server is closing down. Incorrect keys are silently
|
588
|
+
# ignored. The remote server is removed from the database.
|
589
|
+
#
|
590
|
+
# @param [String] my_key being the key of the server being called
|
591
|
+
# @param [Server] server being the record for the remote server that is detaching
|
592
|
+
def detach_server(my_key, server)
|
593
|
+
@logger.verbose("About to detach a remote server: #{server.ident}")
|
594
|
+
|
595
|
+
unless @private_key == my_key
|
596
|
+
@logger.warn("close_remote_server: incorrect key: #{my_key}")
|
597
|
+
return true
|
598
|
+
end
|
599
|
+
@remote_store.delete_if {|s| s.host == server.fqdn}
|
600
|
+
@remote_servers.delete(server)
|
601
|
+
@logger.info("Detached server: #{server.ident}")
|
602
|
+
end
|
603
|
+
|
604
|
+
protected
|
605
|
+
|
606
|
+
private
|
607
|
+
|
608
|
+
# add the given service to the given store,
|
609
|
+
#
|
610
|
+
# Used to add either local or remote services and carry out common checks.
|
611
|
+
#
|
612
|
+
# @param [Array] store which is either local or remote
|
613
|
+
# @param [ServiceRecord] service to be added
|
614
|
+
# @raise [ServiceAlreadyRegistered] when ... a service is already registered!
|
615
|
+
def add_service_to_store(store, service)
|
616
|
+
store.each do |s|
|
617
|
+
if s.same_service?(service) then
|
618
|
+
# there is already a service registered, but is it active?
|
619
|
+
@logger.verbose("There is already a service registered: #{service.ident}")
|
620
|
+
if self.service_missing?(s) then
|
621
|
+
@logger.verbose "Service: #{s.ident} was registered, but did not respond"
|
622
|
+
else
|
623
|
+
raise ServiceAlreadyRegistered, @logger.warn("Service: #{service.address}-#{service.env} already registered")
|
624
|
+
end
|
625
|
+
|
626
|
+
end
|
627
|
+
end
|
628
|
+
# either service was not registered or was missing, so add it
|
629
|
+
store << service
|
630
|
+
@logger.verbose "Added #{service.ident}"
|
631
|
+
end
|
632
|
+
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
|