jerbil 1.3.3 → 1.4.5

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.
@@ -0,0 +1,134 @@
1
+ #
2
+ # Author:: Robert Sharp
3
+ # Copyright:: Copyright (c) 2014 Robert Sharp
4
+ # License:: Open Software Licence v3.0
5
+ #
6
+ # This software is licensed for use under the Open Software Licence v. 3.0
7
+ # The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
8
+ # and in the file copyright.txt. Under the terms of this licence, all derivative works
9
+ # must themselves be licensed under the Open Software Licence v. 3.0
10
+ #
11
+ #
12
+
13
+
14
+ module Jerbil
15
+ # Monitors the network for Jerbil servers and reports to the local server
16
+ #
17
+ # Provides a way to decouple the interactions between the jerbil server
18
+ # and other servers on the network to prevent race conditions or
19
+ # holding up start-up while other servers are discovered
20
+ #
21
+ # The Monitor object is intended to be used in a subprocess after creating
22
+ # the main jerbil server. It scans the LAN for other servers and keeps
23
+ # a record of known servers. When a new server is found, it registers it
24
+ # with the local server and also registers each of its services. If a
25
+ # known server disappears, then it also removes that server (and its services)
26
+ # from the network. If the server left in an orderly manner then it may
27
+ # have already done this, but the server can cope!
28
+ #
29
+ # The subprocess needs to be cleaned up afterwards - does not seem to be possible
30
+ # to either link it with the server's process or tidy up on kill.
31
+ class Monitor
32
+
33
+ # create the monitor object
34
+ #
35
+ # @params options [Hash] options hash as for the Jerbil Server
36
+ # @params jkey [String] jerbil servers private key
37
+ def initialize(options, jkey)
38
+ @options = options
39
+ @env = @options[:environment]
40
+ @jerbil_key = jkey
41
+ @local_server = Jerbil::Servers.create_local_server(@env, @jerbil_key)
42
+ @servers = Hash.new
43
+ @servers[@local_server.fqdn] = @local_server
44
+ @log_opts = Jellog::Logger.get_options(options)
45
+ log_opts = @log_opts.dup
46
+ @logger = Jellog::Logger.new('jerbil-monitor', log_opts)
47
+ @logger.system "Started the Jerbil Monitor"
48
+ self.monitor
49
+ end
50
+
51
+ # start the monitor loop to find and register existing servers
52
+ #
53
+ # Loops round to see what servers are up and adds any that are not
54
+ # already known about. It does this "check_count" times in case it misses
55
+ # a server (the TCP check may not have a long timeout). See
56
+ #
57
+ # It does one loop every :monitor_loop_time seconds (see {Jerbil::Config})
58
+ #
59
+ def monitor
60
+ # create a monitor thread
61
+ loop_time = @options[:loop_time]
62
+ # loop forever
63
+ ljerbil = @local_server.connect
64
+
65
+ check_count = @options[:check_count]
66
+
67
+ check_count.times do |c|
68
+ @logger.info "Starting jerbil server monitor loop: #{c}"
69
+ # set the time until the next loop
70
+ time_to_next_loop = Time.now + loop_time
71
+ # scan the LAN for other monitors
72
+ network_servers = Jerbil::Servers.find_servers(@env,
73
+ @options[:net_address],
74
+ @options[:net_mask],
75
+ @options[:scan_timeout])
76
+ scanned = Array.new
77
+
78
+ # for each discovered server
79
+ network_servers.each do |nserver|
80
+
81
+ scanned << nserver.fqdn
82
+ # skip if already known
83
+ next if @servers.has_key? nserver.fqdn
84
+
85
+ # its new so register with servers
86
+
87
+ rjerbil = nserver.connect
88
+ unless rjerbil.nil?
89
+ begin
90
+ # register local with remote
91
+ rkey = rjerbil.register_server(@local_server, @options[:secret], @env)
92
+ nserver.set_key(rkey)
93
+
94
+ # and register remote with local
95
+ ljerbil.register_server(nserver, @options[:secret], @env)
96
+
97
+ @logger.info "Found server: #{nserver.fqdn}"
98
+
99
+ # Add to local record - could use jerbil itself?
100
+ @servers[nserver.fqdn] = nserver
101
+
102
+
103
+ # now tell my server about these services
104
+
105
+ rjerbil.get_local_services(rkey).each do |rservice|
106
+ ljerbil.register_remote(@jerbil_key, rservice)
107
+ end
108
+
109
+ rescue Jerbil::JerbilAuthenticationError
110
+ @logger.fatal "Invalid Secret key registering with #{nserver.fqdn}"
111
+ @servers[nserver.fqdn] = nserver # save it anyway to stop repeated logging
112
+ end
113
+ end
114
+ end
115
+
116
+ if time_to_next_loop > Time.now then
117
+ @logger.debug "Taking a nap"
118
+ sleep(time_to_next_loop - Time.now)
119
+ end
120
+
121
+ end # loop
122
+
123
+
124
+ rescue => e
125
+ @logger.exception e
126
+ ensure
127
+ @logger.system "Jerbil Monitor complete and closing down"
128
+ @logger.close
129
+ Process.exit!
130
+ end
131
+
132
+
133
+ end
134
+ end
@@ -32,6 +32,10 @@ module Jerbil
32
32
  # Note that the callback parameters do not really need to be considered
33
33
  # if you are using {JerbilService::Base}
34
34
  #
35
+ # Warning - if your hostname is not fully qualified this may not work as expected
36
+ # if you DNS server does not provide expected reverse lookup. Consider using
37
+ # `hostname -f` although *nix dependent.
38
+ #
35
39
  # @param [Symbol] name identifying the service - needs to match /etc/services
36
40
  # or create fails with the exception InvalidService
37
41
  # @param [Symbol] env identify the service's environment. Allows multiple
@@ -42,7 +46,13 @@ module Jerbil
42
46
  # @return [ServiceRecord] of course
43
47
  # @raise [InvalidService] if the service is not registered through /etc/services
44
48
  def initialize(name, env, verify_callback=:verify_callback, stop_callback=nil)
49
+
50
+ # gethostname may npt provide the fqdn
45
51
  @host = Socket.gethostname
52
+ if @host.split('.').length == 1 then
53
+ # no domain name
54
+ @host = Socket.gethostbyname(@host).first
55
+ end
46
56
  @name = name
47
57
  begin
48
58
  @port = Socket.getservbyname(@name.to_s)
@@ -32,14 +32,14 @@ module Jerbil
32
32
  # @param [String] pid_dir path to directory where pid file is to be written
33
33
  # @return [String] the pid
34
34
  # @raise [Jerbil::ServiceConfigError] if the pid file cannot be written to
35
- def Support.write_pid_file(name, env, pid_dir)
36
- pid = Process.pid.to_s
35
+ def Support.write_pid_file(name, env, pid_dir, pid=Process.pid)
36
+ #pid = Process.pid.to_s
37
37
  pid_file = "#{pid_dir}/#{name.to_s}-#{env}.pid"
38
38
  FileUtils.rm_f(pid_file) if File.exists?(pid_file) # avoid permissions probs
39
39
  File.open(pid_file, "w") do |pfile|
40
- pfile.puts pid
40
+ pfile.puts pid.to_s
41
41
  end
42
- return pid
42
+ return pid.to_s
43
43
  rescue Errno::ENOENT
44
44
  # failed to write pid to file
45
45
  raise Jerbil::ServiceConfigError, "Cannot write pid file: #{pid_file}"
@@ -1,13 +1,14 @@
1
1
  # Created by Jevoom
2
2
  #
3
- # 03-Sep-2013
4
- # Ensure jerbil methods are called on the server and not the server record.
3
+ # 17-Oct-2014
4
+ # Add server version to 'jerbil remotes -V' and add system logging for start and
5
+ # end of monitor process.
5
6
 
6
7
  module Jerbil
7
- # version set to 1.3.3
8
- Version = '1.3.3'
9
- # date set to 03-Sep-2013
10
- Version_Date = '03-Sep-2013'
11
- #ident string set to: jerbil-1.3.3 03-Sep-2013
12
- Ident = 'jerbil-1.3.3 03-Sep-2013'
8
+ # version set to 1.4.5
9
+ Version = '1.4.5'
10
+ # date set to 17-Oct-2014
11
+ Version_Date = '17-Oct-2014'
12
+ #ident string set to: jerbil-1.4.5 17-Oct-2014
13
+ Ident = 'jerbil-1.4.5 17-Oct-2014'
13
14
  end
@@ -136,4 +136,15 @@ rescue DRb::DRbConnError
136
136
  end
137
137
 
138
138
  puts "Stopped Jerbil Server" if verbose
139
+
140
+ # puts "Stopping Monitor process" if verbose
141
+ #
142
+ # mpid = Jerbil::Support.get_pid_and_delete_file(:jmonitor, server_env, options[:pid_dir])
143
+ # if mpid then
144
+ # puts "Obtained a pid for monitor: #{mpid}" if verbose
145
+ # Process.kill "SIGKILL", mpid.to_i
146
+ # else
147
+ # puts "No mpid was found!" if verbose
148
+ # end
149
+
139
150
  exit 0
@@ -21,6 +21,7 @@ require 'jerbil/servers'
21
21
  require 'jerbil/config'
22
22
  require 'jerbil/version'
23
23
  require 'jerbil/support'
24
+ require 'jerbil/monitor'
24
25
 
25
26
  require 'jellog'
26
27
  require 'jeckyl'
@@ -157,9 +158,12 @@ end
157
158
 
158
159
 
159
160
 
160
- logger.puts "Logging started for Jerbil Daemon"
161
+ logger.puts "Logging started for Jerbil Daemon" if verbose
161
162
  logger.puts "Daemonized" if verbose && daemonize
162
163
 
164
+ # will only output messages to screen if not daemonised and therefore safe to
165
+ # assume verbose anyway.
166
+
163
167
  my_self = Jerbil::Servers.create_local_server(config[:environment], pkey)
164
168
 
165
169
  logger.puts "Created local server: #{my_self.ident}"
@@ -168,14 +172,31 @@ jerbild = Jerbil::Broker.new(config, pkey)
168
172
 
169
173
  logger.puts "Started Broker"
170
174
 
175
+ logger.puts "Starting Monitor"
176
+
177
+ # create a separate process to look for other servers
178
+ # and log them to this one
179
+ mon_pid = fork do
180
+
181
+ monitor = Jerbil::Monitor.new(config, pkey)
182
+
183
+ # exits automatically
184
+
185
+ end
186
+
171
187
  DRb.start_service(my_self.drb_address, jerbild)
172
188
 
173
189
  logger.puts "Started DRb"
174
190
 
175
- # now create the pid file
176
- Jerbil::Support.write_pid_file(:jerbil, config[:environment], config[:pid_dir])
177
191
 
178
- logger.puts "Written pid #{Process.pid} to pid file"
192
+ # now create the pid files
193
+ jer_pid = Jerbil::Support.write_pid_file(:jerbil, config[:environment], config[:pid_dir])
194
+
195
+ logger.puts "Written Jerbil pid #{jer_pid} to pid file"
196
+
197
+ # Jerbil::Support.write_pid_file(:jmonitor, config[:environment], config[:pid_dir], mon_pid)
198
+ #
199
+ # logger.puts "Written Monitor pid #{mon_pid} to pid file"
179
200
 
180
201
  $0 = "jerbild-#{config[:environment]}"
181
202
 
@@ -33,28 +33,28 @@ describe "Test Jerbil Client Interface" do
33
33
  it "should respond to the old connect method" do
34
34
  client_opts = {:local=>true, :config_file=>config_file, :quiet=>true, :jerbil_env=>:test}
35
35
  JerbilService::Client.connect(RubyTest, client_opts) do |rubytest|
36
- rubytest.action.should == 'Hello'
37
- rubytest.host.should == localhost
36
+ expect(rubytest.action).to eq('Hello')
37
+ expect(rubytest.host).to eq(localhost)
38
38
  end
39
39
  end
40
40
 
41
41
  it "should respond to the new find_services method" do
42
42
  JerbilService::Client.find_services(:first, RubyTest, @client_opts) do |rubytest|
43
- rubytest.action.should == 'Hello'
44
- rubytest.host.should == localhost
43
+ expect(rubytest.action).to eq('Hello')
44
+ expect(rubytest.host).to eq(localhost)
45
45
  end
46
46
  end
47
47
 
48
48
  it "should respond to the new find_services method with local service" do
49
49
  JerbilService::Client.find_services(:local, RubyTest, @client_opts) do |rubytest|
50
- rubytest.action.should == 'Hello'
51
- rubytest.host.should == localhost
50
+ expect(rubytest.action).to eq('Hello')
51
+ expect(rubytest.host).to eq(localhost)
52
52
  end
53
53
  end
54
54
 
55
55
  it "should work with multiple client call" do
56
56
  JerbilService::Client.find_services(:all, RubyTest, @client_opts) do |rubytest|
57
- rubytest.action.should == 'Hello'
57
+ expect(rubytest.action).to eq('Hello')
58
58
  end
59
59
  end
60
60
 
@@ -66,26 +66,26 @@ describe "Test Jerbil Client Interface" do
66
66
  options[:output] = log_file
67
67
  options[:quiet] = false
68
68
  JerbilService::Client.find_services(:local, RubyTest, options) do |rubytest|
69
- rubytest.action.should == 'Hello'
69
+ expect(rubytest.action).to eq('Hello')
70
70
  end
71
71
  log_file.close
72
72
  log = File.readlines(log_filename)
73
- log[0].should match(/^Welcome/)
73
+ expect(log[0]).to match(/^Welcome/)
74
74
  end
75
75
 
76
76
  it "should not respond to an unknown method" do
77
77
  JerbilService::Client.find_services(:first, RubyTest, @client_opts) do |rubytest|
78
- lambda{rubytest.unlikely_method}.should raise_error(NoMethodError)
78
+ expect {rubytest.unlikely_method}.to raise_error(NoMethodError)
79
79
  end
80
80
  end
81
81
 
82
82
  it "should not respond to an unknown search key" do
83
- lambda{JerbilService::Client.find_services(:last, RubyTest, @client_opts)}.should raise_error(ArgumentError)
83
+ expect {JerbilService::Client.find_services(:last, RubyTest, @client_opts)}.to raise_error(ArgumentError)
84
84
  end
85
85
 
86
86
  it "should not allow the stop_callback to be called" do
87
87
  JerbilService::Client.find_services(:first, RubyTest, @client_opts) do |rubytest|
88
- lambda{rubytest.stop_callback}.should raise_error(Jerbil::UnauthorizedMethod)
88
+ expect {rubytest.stop_callback}.to raise_error(Jerbil::UnauthorizedMethod)
89
89
  end
90
90
  end
91
91
 
@@ -97,18 +97,18 @@ describe "Jerbil Clients that do different things" do
97
97
  end
98
98
 
99
99
  it "should not find an invalid service" do
100
- lambda{JerbilService::Client.connect(Blabla)}.should raise_error(NameError)
100
+ expect {JerbilService::Client.connect(Blabla)}.to raise_error(NameError)
101
101
  end
102
102
 
103
103
  it "should find a local service" do
104
104
  JerbilService::Client.connect(RubyTest, @client_opts) do |client|
105
- client.action.should == 'Hello'
105
+ expect(client.action).to eq('Hello')
106
106
  end
107
107
  end
108
108
 
109
109
  it "should not find a local service if it thinks it is somewhere else" do
110
- Socket.stub(:gethostname).and_return('germanicus.osburn-sharp.ath.cx', 'lucius.osburn-sharp.ath.cx')
111
- lambda{JerbilService::Client.connect(RubyTest, @client_opts)}.should raise_error(Jerbil::ServiceNotFound)
110
+ allow(Socket).to receive_message_chain(:gethostname).and_return('germanicus.osburn-sharp.ath.cx', 'lucius.osburn-sharp.ath.cx')
111
+ expect {JerbilService::Client.connect(RubyTest, @client_opts)}.to raise_error(Jerbil::ServiceNotFound)
112
112
  end
113
113
 
114
114
  end
@@ -32,7 +32,6 @@ describe "A local Jerbil Session running under a daemon" do
32
32
  end
33
33
 
34
34
  before(:each) do
35
-
36
35
  my_conf = Jerbil::Config.new(conf_file)
37
36
  test_server = Jerbil::Servers.get_local_server(my_conf[:environment])
38
37
  @my_session = test_server.connect
@@ -44,21 +43,21 @@ describe "A local Jerbil Session running under a daemon" do
44
43
 
45
44
 
46
45
  it "should be easily created" do
47
- @my_session.started.should be_true
48
- @my_session.registrations.should == @registrations
49
- @my_session.service_count.should == @start_count
50
- @my_session.get_all.should == []
46
+ expect(@my_session.started).to be_kind_of(Time)
47
+ expect(@my_session.registrations).to eq(@registrations)
48
+ expect(@my_session.service_count).to eq(@start_count)
49
+ expect(@my_session.get_all).to eq([])
51
50
  end
52
51
 
53
52
  it "should be easy to add a service" do
54
53
  @my_session.register(@my_service)
55
- @my_session.registrations.should == @registrations + 1
56
- @my_session.service_count.should == @start_count + 1
54
+ expect(@my_session.registrations).to eq(@registrations + 1)
55
+ expect(@my_session.service_count).to eq(@start_count + 1)
57
56
  services = @my_session.get_all(:ignore_access => true)
58
- services[0].should == @my_service
57
+ expect(services[0]).to eq(@my_service)
59
58
  service = @my_session.get_local(:ignore_access => true)
60
- service.should == @my_service
61
- @my_session.find(:name=>'Another', :ignore_access => true).should == []
59
+ expect(service).to eq(@my_service)
60
+ expect(@my_session.find(:name=>'Another', :ignore_access => true)).to eq([])
62
61
  @my_session.remove(@my_service)
63
62
  end
64
63
 
@@ -67,13 +66,13 @@ describe "A local Jerbil Session running under a daemon" do
67
66
  it "should be easy to remove a service" do
68
67
  @my_session.register(@my_service)
69
68
  @my_session.remove(@my_service)
70
- @my_session.service_count.should == @start_count
69
+ expect(@my_session.service_count).to eq(@start_count)
71
70
  end
72
71
 
73
72
  it "should do nothing if you remove an unregistered service" do
74
73
  @my_session.register(@my_service)
75
74
  @my_session.remove(@a_service)
76
- @my_session.service_count.should == @start_count + 1
75
+ expect(@my_session.service_count).to eq(@start_count + 1)
77
76
  @my_session.remove(@my_service)
78
77
  end
79
78
 
@@ -13,7 +13,7 @@
13
13
  # The purpose of these tests is to check the local interface to a Jerbil Broker only
14
14
  #
15
15
  require 'rubygems'
16
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
16
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
17
17
  require 'jerbil/servers'
18
18
  require 'jerbil/service'
19
19
  require 'jerbil/config'
@@ -21,7 +21,7 @@ require 'jerbil'
21
21
  require 'jellog'
22
22
 
23
23
 
24
- conf_file = File.expand_path(File.dirname(__FILE__) + '/../test/conf.d/jerbil_local.rb')
24
+ conf_file = File.expand_path(File.join(File.dirname(File.dirname(__FILE__)), 'test', 'conf.d','jerbil_local.rb'))
25
25
 
26
26
 
27
27
  describe "A local Jerbil Session" do
@@ -45,45 +45,45 @@ describe "A local Jerbil Session" do
45
45
  end
46
46
 
47
47
  it "should be easily created" do
48
- @my_session.started.should be_true
49
- @my_session.registrations.should == 0
50
- @my_session.service_count.should == 0
51
- @my_session.local_service_count.should == 0
52
- @my_session.remote_service_count.should == 0
53
- @my_session.get_all.should == []
48
+ expect(@my_session.started).to be_kind_of(Time)
49
+ expect(@my_session.registrations).to eq(0)
50
+ expect(@my_session.service_count).to eq(0)
51
+ expect(@my_session.local_service_count).to eq(0)
52
+ expect(@my_session.remote_service_count).to eq(0)
53
+ expect(@my_session.get_all).to eq([])
54
54
  end
55
55
 
56
56
  it "should be easy to add a service" do
57
57
  @my_session.register(@my_service)
58
- @my_session.registrations.should == 1
59
- @my_session.service_count.should == 1
60
- @my_session.local_service_count.should == 1
61
- @my_session.remote_service_count.should == 0
58
+ expect(@my_session.registrations).to eq(1)
59
+ expect(@my_session.service_count).to eq(1)
60
+ expect(@my_session.local_service_count).to eq(1)
61
+ expect(@my_session.remote_service_count).to eq(0)
62
62
  services = @my_session.get_all(:ignore_access => true)
63
- services[0].should == @my_service
63
+ expect(services[0]).to eq(@my_service)
64
64
  service = @my_session.get_local(:ignore_access => true)
65
- service.should == @my_service
66
- @my_session.find(:name=>'Another', :ignore_access => true).should == []
65
+ expect(service).to eq(@my_service)
66
+ expect(@my_session.find(:name=>'Another', :ignore_access => true)).to eq([])
67
67
  @my_session.remove(@my_service)
68
68
  end
69
69
 
70
70
  it "should not be possible to register the same service twice" do
71
- @my_service.should_receive(:connect).and_return(true) # make it appear the service is live
71
+ allow(@my_service).to receive_messages(connect:true) # make it appear the service is live
72
72
  @my_session.register(@my_service)
73
- lambda{@my_session.register(@my_service)}.should raise_error{Jerbil::ServiceAlreadyRegistered}
73
+ expect {@my_session.register(@my_service)}.to raise_error{Jerbil::ServiceAlreadyRegistered}
74
74
  @my_session.remove(@my_service)
75
75
  end
76
76
 
77
77
  it "should be easy to remove a service" do
78
78
  @my_session.register(@my_service)
79
79
  @my_session.remove(@my_service)
80
- @my_session.service_count.should == 0
80
+ expect(@my_session.service_count).to eq(0)
81
81
  end
82
82
 
83
83
  it "should do nothing if you remove an unregistered service" do
84
84
  @my_session.register(@my_service)
85
85
  @my_session.remove(@a_service)
86
- @my_session.service_count.should == 1
86
+ expect(@my_session.service_count).to eq(1)
87
87
 
88
88
  end
89
89