sonar_connector 0.8.5
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/bin/sonar-connector +69 -0
- data/config/config.example.json +82 -0
- data/lib/sonar_connector.rb +40 -0
- data/lib/sonar_connector/commands/command.rb +21 -0
- data/lib/sonar_connector/commands/commit_seppuku_command.rb +15 -0
- data/lib/sonar_connector/commands/increment_status_value_command.rb +14 -0
- data/lib/sonar_connector/commands/send_admin_email_command.rb +12 -0
- data/lib/sonar_connector/commands/update_disk_usage_command.rb +13 -0
- data/lib/sonar_connector/commands/update_status_command.rb +16 -0
- data/lib/sonar_connector/config.rb +166 -0
- data/lib/sonar_connector/connectors/base.rb +243 -0
- data/lib/sonar_connector/connectors/dummy_connector.rb +17 -0
- data/lib/sonar_connector/connectors/seppuku_connector.rb +26 -0
- data/lib/sonar_connector/consumer.rb +94 -0
- data/lib/sonar_connector/controller.rb +164 -0
- data/lib/sonar_connector/emailer.rb +16 -0
- data/lib/sonar_connector/rspec/spec_helper.rb +61 -0
- data/lib/sonar_connector/status.rb +43 -0
- data/lib/sonar_connector/utils.rb +39 -0
- data/script/console +10 -0
- data/spec/sonar_connector/commands/command_spec.rb +34 -0
- data/spec/sonar_connector/commands/commit_seppuku_command_spec.rb +25 -0
- data/spec/sonar_connector/commands/increment_status_value_command_spec.rb +25 -0
- data/spec/sonar_connector/commands/send_admin_email_command_spec.rb +14 -0
- data/spec/sonar_connector/commands/update_disk_usage_command_spec.rb +21 -0
- data/spec/sonar_connector/commands/update_status_command_spec.rb +24 -0
- data/spec/sonar_connector/config_spec.rb +93 -0
- data/spec/sonar_connector/connectors/base_spec.rb +207 -0
- data/spec/sonar_connector/connectors/dummy_connector_spec.rb +22 -0
- data/spec/sonar_connector/connectors/seppuku_connector_spec.rb +37 -0
- data/spec/sonar_connector/consumer_spec.rb +116 -0
- data/spec/sonar_connector/controller_spec.rb +46 -0
- data/spec/sonar_connector/emailer_spec.rb +36 -0
- data/spec/sonar_connector/status_spec.rb +78 -0
- data/spec/sonar_connector/utils_spec.rb +62 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +6 -0
- metadata +235 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Trampoline Systems Ltd
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Trampoline SONAR Connector framework
|
2
|
+
|
3
|
+
== Dependencies
|
4
|
+
|
5
|
+
=== Jruby
|
6
|
+
|
7
|
+
Here's how to install jruby 1.4.0 on OS X:
|
8
|
+
|
9
|
+
wget http://jruby.kenai.com/downloads/1.4.0/jruby-bin-1.4.0.tar.gz
|
10
|
+
sudo tar xfvz jruby-bin-1.4.0.tar.gz -C /usr/local/
|
11
|
+
ln -s /usr/local/jruby/bin/jruby /usr/bin/jruby
|
12
|
+
ln -s /usr/local/jruby/bin/rake /usr/bin/jrake
|
13
|
+
ln -s /usr/local/jruby/bin/gem /usr/bin/jgem
|
14
|
+
ln -s /usr/local/jruby/bin/jirb /usr/bin/jirb
|
15
|
+
|
16
|
+
== Copyright
|
17
|
+
|
18
|
+
Copyright (c) 2010 Trampoline Systems Ltd. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "sonar_connector"
|
8
|
+
gem.summary = %Q{A behind-the-firewall connector for Trampoline SONAR}
|
9
|
+
gem.description = %Q{Framework that allows arbitrary push and pull connectors to send data to an instance of the Trampoline SONAR server}
|
10
|
+
gem.email = "hello@empire42.com"
|
11
|
+
gem.homepage = "http://github.com/trampoline/sonar-connector"
|
12
|
+
gem.authors = ["Peter MacRobert", "Mark Meyer"]
|
13
|
+
|
14
|
+
gem.add_dependency "actionmailer", "= 2.3.10"
|
15
|
+
gem.add_dependency "actionmailer_extensions", ">= 0.4.2"
|
16
|
+
gem.add_dependency "json_pure", ">= 1.2.2"
|
17
|
+
gem.add_dependency "uuidtools", ">= 2.1.1"
|
18
|
+
gem.add_dependency "sonar_connector_filestore", ">= 0.1.0"
|
19
|
+
|
20
|
+
gem.add_development_dependency "rspec", ">= 1.2.8"
|
21
|
+
gem.add_development_dependency "rr", ">= 0.10.5"
|
22
|
+
end
|
23
|
+
Jeweler::GemcutterTasks.new
|
24
|
+
rescue LoadError
|
25
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'spec/rake/spectask'
|
29
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
35
|
+
spec.libs << 'lib' << 'spec'
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
task :spec => :check_dependencies
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.8.5
|
data/bin/sonar-connector
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'sonar_connector')
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
config_filename = File.expand_path File.join(Dir.pwd, "config", "config.json")
|
7
|
+
mode = nil
|
8
|
+
install_path = nil
|
9
|
+
|
10
|
+
ARGV.options do |opts|
|
11
|
+
script_name = File.basename($0)
|
12
|
+
|
13
|
+
opts.banner = "Usage: #{script_name} OPTION"
|
14
|
+
|
15
|
+
opts.separator "Run modes:"
|
16
|
+
opts.on("--start", "Start the connector") { mode = :start }
|
17
|
+
opts.on("--check", "Validate the connector config") { mode = :check }
|
18
|
+
opts.on("--install=PATH", String, "Install the connector working dir and default config to the file system") {|p|
|
19
|
+
install_path = p
|
20
|
+
mode = :install
|
21
|
+
}
|
22
|
+
opts.on("--console", "Run IRB console in connector framework environment") { mode = :console }
|
23
|
+
|
24
|
+
opts.separator "Options:"
|
25
|
+
|
26
|
+
opts.on("-c", "--config=FILE", String, "Override the path to the config file.") {|s| config_filename = File.expand_path s}
|
27
|
+
|
28
|
+
opts.separator "Misc:"
|
29
|
+
opts.on_tail("-v", "--version", "Show version") { mode = :version }
|
30
|
+
opts.on_tail("-h", "--help", "Show this message")
|
31
|
+
opts.parse!
|
32
|
+
end
|
33
|
+
|
34
|
+
case mode
|
35
|
+
when :start
|
36
|
+
puts "Starting SONAR Connector from config file: #{config_filename}"
|
37
|
+
connector = Sonar::Connector::Controller.new(config_filename)
|
38
|
+
puts "Connector bootstrapped successfully, check log files for details."
|
39
|
+
connector.start
|
40
|
+
exit
|
41
|
+
|
42
|
+
when :check
|
43
|
+
puts "Checking config file: #{config_filename}"
|
44
|
+
Sonar::Connector::Controller.new(config_filename)
|
45
|
+
puts "...clean."
|
46
|
+
exit
|
47
|
+
when :install
|
48
|
+
path = File.expand_path install_path
|
49
|
+
|
50
|
+
if File.directory?(path)
|
51
|
+
puts "Error: Directory '#{path}' already exists, aborting."
|
52
|
+
exit(1)
|
53
|
+
end
|
54
|
+
|
55
|
+
%W{config log var}.each {|dir| FileUtils.mkdir_p File.join(path, dir)}
|
56
|
+
FileUtils.cp File.join(Sonar::Connector::ROOT, '..', "config", "config.example.json"), File.join(path, 'config', 'config.json')
|
57
|
+
puts "Success: Set up working directory '#{path}' and associated subdirs."
|
58
|
+
exit
|
59
|
+
when :console
|
60
|
+
lib_path = File.expand_path File.join(File.dirname(__FILE__), '..', 'lib')
|
61
|
+
Kernel.system "irb -rubygems -I #{lib_path} -r sonar_connector.rb"
|
62
|
+
exit
|
63
|
+
when :version
|
64
|
+
version_file = File.join File.expand_path(File.dirname(__FILE__)), "..", "VERSION"
|
65
|
+
puts "SONAR Connector Framework #{File.read(version_file)}"
|
66
|
+
exit
|
67
|
+
else
|
68
|
+
puts ARGV.options
|
69
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
{
|
2
|
+
/* log level must be one of: "debug", "info", "warn", "error", "fatal" */
|
3
|
+
"log_level" : "debug",
|
4
|
+
|
5
|
+
/* max log file size in megabytes */
|
6
|
+
"log_file_max_size" : "10",
|
7
|
+
|
8
|
+
/* number of log files to keep */
|
9
|
+
"log_files_to_keep" : "7",
|
10
|
+
|
11
|
+
"email_settings": {
|
12
|
+
"admin_recipients": ["admin@server.local"],
|
13
|
+
"admin_sender": "Sonar Connector <noreply@server.local>",
|
14
|
+
"perform_deliveries": false,
|
15
|
+
|
16
|
+
/* options are ["smtp", "sendmail", "test"] */
|
17
|
+
"delivery_method": "smtp",
|
18
|
+
"save_emails_to_disk": true,
|
19
|
+
|
20
|
+
"smtp_settings": {
|
21
|
+
"address": "127.0.0.1",
|
22
|
+
"port": 25,
|
23
|
+
"domain": "server.local",
|
24
|
+
"user_name": null,
|
25
|
+
"password": null,
|
26
|
+
|
27
|
+
/* options are ["plain", "login", "cram_md5"] */
|
28
|
+
"authentication": null
|
29
|
+
},
|
30
|
+
|
31
|
+
"sendmail_settings": {
|
32
|
+
"location": "/usr/sbin/sendmail",
|
33
|
+
"arguments": "-i -t -f nobody@localhost"
|
34
|
+
}
|
35
|
+
},
|
36
|
+
|
37
|
+
/*
|
38
|
+
Specific configuration for each connector. Each connector must have
|
39
|
+
a class and a unique name. The require load path can also be specified if necessary.
|
40
|
+
Note that each connector type may have further configuration options
|
41
|
+
that are specific to the connector class.
|
42
|
+
*/
|
43
|
+
"connectors": [
|
44
|
+
{
|
45
|
+
"class": "Sonar::Connector::ImapPullConnector",
|
46
|
+
"require": "sonar_imap_pull_connector",
|
47
|
+
"name": "gmail_1",
|
48
|
+
"repeat_delay": 10,
|
49
|
+
"host": "imap.gmail.com",
|
50
|
+
"user": "foo@bar.com",
|
51
|
+
"password": "---",
|
52
|
+
"folders": "[Gmail]/All Mail"
|
53
|
+
}
|
54
|
+
,
|
55
|
+
{
|
56
|
+
"class": "Sonar::Connector::ImapPullConnector",
|
57
|
+
"require": "sonar_imap_pull_connector",
|
58
|
+
"name": "gmail_2",
|
59
|
+
"repeat_delay": 10,
|
60
|
+
"host": "imap.gmail.com",
|
61
|
+
"user": "baz@bar.com",
|
62
|
+
"password": "---",
|
63
|
+
"folders": "[Google Mail]/All Mail"
|
64
|
+
}
|
65
|
+
,
|
66
|
+
{
|
67
|
+
"class": "Sonar::Connector::SonarPushConnector",
|
68
|
+
"require": "sonar_push_connector",
|
69
|
+
"name": "sonar_push",
|
70
|
+
"repeat_delay": 10,
|
71
|
+
"source_connectors": ["gmail_1", "gmail_2"],
|
72
|
+
"uri": "http://localhost:3000/api/1_0/rfc822_messages",
|
73
|
+
"connector_credentials": "---"
|
74
|
+
},
|
75
|
+
{
|
76
|
+
"class": "Sonar::Connector::SeppukuConnector",
|
77
|
+
"name": "seppuku",
|
78
|
+
"enabled": true,
|
79
|
+
"repeat_delay": 43200
|
80
|
+
}
|
81
|
+
]
|
82
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sonar
|
2
|
+
module Connector
|
3
|
+
ROOT = File.dirname(__FILE__) unless Sonar::Connector.const_defined?("ROOT")
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
$:.unshift(File.expand_path("..", __FILE__))
|
9
|
+
|
10
|
+
# Load external deps
|
11
|
+
require 'active_support'
|
12
|
+
require 'json'
|
13
|
+
require 'yaml'
|
14
|
+
require 'thread'
|
15
|
+
require 'logger'
|
16
|
+
require 'action_mailer'
|
17
|
+
require 'actionmailer_extensions'
|
18
|
+
require 'fileutils'
|
19
|
+
require 'sonar_connector_filestore'
|
20
|
+
|
21
|
+
# Load internal classes
|
22
|
+
%W(
|
23
|
+
controller
|
24
|
+
config
|
25
|
+
status
|
26
|
+
consumer
|
27
|
+
emailer
|
28
|
+
utils
|
29
|
+
connectors/base
|
30
|
+
connectors/dummy_connector
|
31
|
+
connectors/seppuku_connector
|
32
|
+
commands/command
|
33
|
+
commands/update_status_command
|
34
|
+
commands/send_admin_email_command
|
35
|
+
commands/update_disk_usage_command
|
36
|
+
commands/increment_status_value_command
|
37
|
+
commands/commit_seppuku_command
|
38
|
+
).each do |file|
|
39
|
+
require File.join('sonar_connector', file)
|
40
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sonar
|
2
|
+
module Connector
|
3
|
+
|
4
|
+
##
|
5
|
+
# Base command class that all commands should subclass.
|
6
|
+
|
7
|
+
class Command
|
8
|
+
|
9
|
+
attr_accessor :proc
|
10
|
+
|
11
|
+
def initialize(proc)
|
12
|
+
@proc = proc
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(context = nil)
|
16
|
+
context.instance_eval(&@proc)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sonar
|
2
|
+
module Connector
|
3
|
+
|
4
|
+
class CommitSeppukuCommand < Sonar::Connector::Command
|
5
|
+
def initialize
|
6
|
+
l = lambda do
|
7
|
+
# controller is in scope here because we've jumped thru some serious hoops
|
8
|
+
# and shaved the hell out of a yak or three.
|
9
|
+
Thread.new {controller.shutdown_lambda.call}
|
10
|
+
end
|
11
|
+
super(l)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Sonar
|
2
|
+
module Connector
|
3
|
+
|
4
|
+
class IncrementStatusValueCommand < Sonar::Connector::Command
|
5
|
+
def initialize(connector, field, value = 1)
|
6
|
+
l = lambda do
|
7
|
+
current = status[connector.name] ? status[connector.name][field].to_i : 0
|
8
|
+
status.set connector.name, field, current+value
|
9
|
+
end
|
10
|
+
super(l)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Sonar
|
2
|
+
module Connector
|
3
|
+
class UpdateDiskUsageCommand < Sonar::Connector::Command
|
4
|
+
def initialize(connector)
|
5
|
+
l = lambda do
|
6
|
+
du = (Sonar::Connector::Utils.du(connector.connector_dir).to_f / 1024).round
|
7
|
+
status.set connector.name, 'disk_usage', "#{du} Kb"
|
8
|
+
end
|
9
|
+
super(l)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sonar
|
2
|
+
module Connector
|
3
|
+
|
4
|
+
ACTION_OK = 'ok'
|
5
|
+
ACTION_FAILED = 'failed'
|
6
|
+
|
7
|
+
class UpdateStatusCommand < Sonar::Connector::Command
|
8
|
+
def initialize(connector, field, value)
|
9
|
+
l = lambda do
|
10
|
+
status.set connector.name, field, value
|
11
|
+
end
|
12
|
+
super(l)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Sonar
|
2
|
+
module Connector
|
3
|
+
class InvalidConfig < RuntimeError; end
|
4
|
+
|
5
|
+
class Config
|
6
|
+
|
7
|
+
# base params
|
8
|
+
attr_reader :base_dir
|
9
|
+
attr_reader :log_dir
|
10
|
+
attr_reader :connectors_dir
|
11
|
+
attr_reader :controller_log_file
|
12
|
+
attr_reader :status_file
|
13
|
+
attr_reader :connectors
|
14
|
+
attr_reader :email_settings
|
15
|
+
|
16
|
+
# configurable: logger params
|
17
|
+
attr_reader :log_level
|
18
|
+
attr_reader :log_file_max_size
|
19
|
+
attr_reader :log_files_to_keep
|
20
|
+
|
21
|
+
# Entry-point for creating and setting the CONFIG instance.
|
22
|
+
# Give it a path to the JSON settings file and it'll do the rest.
|
23
|
+
def self.load(config_file)
|
24
|
+
config = Config.new(config_file).parse
|
25
|
+
Sonar::Connector.const_set("CONFIG", config)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Helper method to read and parse JSON file from disk. Abstracted for testing purposes.
|
29
|
+
def self.read_json_file(config_file)
|
30
|
+
JSON.parse IO.read(config_file)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(config_file)
|
34
|
+
@config_file = config_file
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse
|
38
|
+
@raw_config = Config.read_json_file(config_file)
|
39
|
+
|
40
|
+
# extract the core config params
|
41
|
+
@base_dir = parse_base_dir @raw_config["base_dir"]
|
42
|
+
@log_dir = File.join @base_dir, 'log'
|
43
|
+
@connectors_dir = File.join @base_dir, 'var'
|
44
|
+
@controller_log_file = File.join @log_dir, 'controller.log'
|
45
|
+
@status_file = File.join @base_dir, 'status.yml'
|
46
|
+
@log_level = parse_log_level @raw_config["log_level"]
|
47
|
+
@log_file_max_size = parse_log_file_max_size @raw_config["log_file_max_size"]
|
48
|
+
@log_files_to_keep = parse_log_files_to_keep @raw_config["log_files_to_keep"]
|
49
|
+
@email_settings = parse_email_settings @raw_config["email_settings"]
|
50
|
+
|
51
|
+
# extract each connector, locate its class and attempt to parse its config
|
52
|
+
@connectors = parse_connectors @raw_config["connectors"]
|
53
|
+
|
54
|
+
associate_connector_dependencies! @connectors
|
55
|
+
|
56
|
+
self
|
57
|
+
rescue JSON::ParserError => e
|
58
|
+
raise InvalidConfig.new("Config file #{config_file} is not in a valid JSON format. Please check the contents carefully. This is the exact error: \n#{e.message}")
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
attr_reader :config_file
|
64
|
+
attr_reader :raw_config
|
65
|
+
|
66
|
+
def parse_base_dir(base_dir)
|
67
|
+
d = base_dir.blank? ? File.dirname(File.dirname(@config_file)) : base_dir
|
68
|
+
raise InvalidConfig.new("#{d} not a valid directory") unless File.directory?(d)
|
69
|
+
d
|
70
|
+
end
|
71
|
+
|
72
|
+
def parse_log_level(log_level)
|
73
|
+
raise InvalidConfig.new("Config option 'log_level' is a required parameter.") if log_level.blank?
|
74
|
+
valid_log_levels = ["debug", "info", "warn", "error", "fatal"]
|
75
|
+
raise InvalidConfig.new("unknown log_level #{log_level}") unless valid_log_levels.include?(log_level)
|
76
|
+
Logger.const_get log_level.upcase
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_log_file_max_size(log_file_max_size)
|
80
|
+
raise InvalidConfig.new("invalid log_file_max_size #{log_file_max_size}") if !log_file_max_size.blank? && log_file_max_size.to_i == 0
|
81
|
+
log_file_max_size.blank? ? 10*1024*1024 : log_file_max_size.to_i*1024*1024
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_log_files_to_keep(log_files_to_keep)
|
85
|
+
raise InvalidConfig.new("invalid log_files_to_keep #{log_files_to_keep}") if !log_files_to_keep.blank? && log_files_to_keep.to_i == 0
|
86
|
+
log_files_to_keep.blank? ? 10 : log_files_to_keep.to_i
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_email_settings(settings)
|
90
|
+
ActionMailer::Base.perform_deliveries = settings["perform_deliveries"]
|
91
|
+
ActionMailer::Base.delivery_method = settings["delivery_method"].to_sym
|
92
|
+
ActionMailer::Base.raise_delivery_errors = true
|
93
|
+
|
94
|
+
# ActionMailer needs the smtp and sendmail settings hashes to have symbols for keys
|
95
|
+
ActionMailer::Base.smtp_settings = symbolise_hash_keys settings["smtp_settings"]
|
96
|
+
ActionMailer::Base.sendmail_settings = symbolise_hash_keys settings["sendmail_settings"]
|
97
|
+
|
98
|
+
ActionMailer::Base.save_emails_to_disk = settings["save_emails_to_disk"]
|
99
|
+
ActionMailer::Base.email_output_dir = File.join @base_dir, 'sent_administrator_emails'
|
100
|
+
ActionMailer::Base.safe_recipients = settings["admin_recipients"].to_a
|
101
|
+
settings
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_connectors(connectors_config)
|
105
|
+
raise InvalidConfig.new("Connector parameter must be an array and cannot be empty") unless connectors_config.instance_of?(Array) && !connectors_config.empty?
|
106
|
+
|
107
|
+
c = []
|
108
|
+
connectors_config.each do |config|
|
109
|
+
c << parse_connector(config)
|
110
|
+
end
|
111
|
+
|
112
|
+
raise InvalidConfig.new("Connector names must be unique. You supplied: #{c.map(&:name).inspect}") if c.map(&:name).uniq.size != c.size
|
113
|
+
c
|
114
|
+
end
|
115
|
+
|
116
|
+
def parse_connector(config)
|
117
|
+
|
118
|
+
# Load the require first, if specified
|
119
|
+
begin
|
120
|
+
require config["require"] unless config["require"].blank?
|
121
|
+
rescue MissingSourceFile
|
122
|
+
raise InvalidConfig.new("Error with parameter 'require' in connector settings '#{config.inspect}': require failed - check that the path is correct.")
|
123
|
+
end
|
124
|
+
|
125
|
+
# Insist that class is specified
|
126
|
+
raise InvalidConfig.new("Error with parameter 'class' in connector settings '#{config.inspect}': class must be specified.") if config["class"].blank?
|
127
|
+
|
128
|
+
# Attempt to load the class definition
|
129
|
+
begin
|
130
|
+
klass = config["class"].constantize
|
131
|
+
rescue
|
132
|
+
raise InvalidConfig.new("Error with parameter 'class' in connector settings '#{config.inspect}': could not load class.")
|
133
|
+
end
|
134
|
+
|
135
|
+
# sanity-check that the connector class subclasses the base
|
136
|
+
raise InvalidConfig.new("Connector class #{klass.name} must subclass Sonar::Connector::Base") unless klass.ancestors.include?(Sonar::Connector::Base)
|
137
|
+
klass.new(config, self)
|
138
|
+
end
|
139
|
+
|
140
|
+
def symbolise_hash_keys(hash)
|
141
|
+
return nil unless hash
|
142
|
+
hash.keys.inject({}){|acc, k| acc[k.to_sym] = hash[k]; acc}
|
143
|
+
end
|
144
|
+
|
145
|
+
# Find all connectors with "source_connectors" specified in config, and map these
|
146
|
+
# associations to the connector instances.
|
147
|
+
def associate_connector_dependencies!(connectors)
|
148
|
+
connectors.each do |connector|
|
149
|
+
source_names = [*connector.raw_config["source_connectors"]].compact
|
150
|
+
next if source_names.blank?
|
151
|
+
|
152
|
+
source_connectors = source_names.map do |source_name|
|
153
|
+
c = connectors.select{|connector2| connector2.name == source_name}.first
|
154
|
+
raise InvalidConfig.new("Connector '#{connector.name}' references a source connector '#{source_name}' but no such connector name is defined.") unless c
|
155
|
+
raise InvalidConfig.new("Connector '#{connector.name}' cannot have itself as a source connector.") if c == connector
|
156
|
+
c
|
157
|
+
end
|
158
|
+
|
159
|
+
connector.send :source_connectors=, source_connectors
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|