ocp_registry 0.0.1.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +25 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +65 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/bin/ocp_registry +28 -0
- data/config/example-mysql.yml +40 -0
- data/config/example-sqlite.yml +33 -0
- data/lib/ocp_registry.rb +29 -0
- data/lib/ocp_registry/api_controller.rb +146 -0
- data/lib/ocp_registry/application_manager.rb +213 -0
- data/lib/ocp_registry/cloud_manager/mock.rb +5 -0
- data/lib/ocp_registry/cloud_manager/mock/mock.rb +191 -0
- data/lib/ocp_registry/cloud_manager/mock/model.rb +22 -0
- data/lib/ocp_registry/cloud_manager/openstack.rb +4 -0
- data/lib/ocp_registry/cloud_manager/openstack/cinder_helper.rb +27 -0
- data/lib/ocp_registry/cloud_manager/openstack/keystone_helper.rb +57 -0
- data/lib/ocp_registry/cloud_manager/openstack/nova_helper.rb +37 -0
- data/lib/ocp_registry/cloud_manager/openstack/openstack.rb +126 -0
- data/lib/ocp_registry/common.rb +54 -0
- data/lib/ocp_registry/config.rb +96 -0
- data/lib/ocp_registry/db/001_db_initialize.rb +16 -0
- data/lib/ocp_registry/error.rb +16 -0
- data/lib/ocp_registry/mail_client.rb +141 -0
- data/lib/ocp_registry/models.rb +7 -0
- data/lib/ocp_registry/models/registry_application.rb +10 -0
- data/lib/ocp_registry/runner.rb +47 -0
- data/lib/ocp_registry/version.rb +3 -0
- data/lib/ocp_registry/yaml_helper.rb +23 -0
- data/mail_template/approve_admin.erb +14 -0
- data/mail_template/approve_user.erb +22 -0
- data/mail_template/refuse_admin.erb +16 -0
- data/mail_template/refuse_user.erb +17 -0
- data/mail_template/request_admin.erb +15 -0
- data/mail_template/request_user.erb +16 -0
- data/ocp_registry.gemspec +34 -0
- data/public/bootstrap/css/bootstrap-responsive.css +1109 -0
- data/public/bootstrap/css/bootstrap-responsive.min.css +9 -0
- data/public/bootstrap/css/bootstrap.css +6167 -0
- data/public/bootstrap/css/bootstrap.min.css +9 -0
- data/public/bootstrap/img/glyphicons-halflings-white.png +0 -0
- data/public/bootstrap/img/glyphicons-halflings.png +0 -0
- data/public/bootstrap/js/bootstrap.js +2280 -0
- data/public/bootstrap/js/bootstrap.min.js +6 -0
- data/public/common.css +104 -0
- data/public/favicon.ico +0 -0
- data/public/images/loading.gif +0 -0
- data/public/jquery-1.10.2.min.js +6 -0
- data/public/jquery-1.10.2.min.map +1 -0
- data/public/jquery.json-2.4.min.js +23 -0
- data/public/noty/.gitignore +8 -0
- data/public/noty/LICENSE.txt +20 -0
- data/public/noty/README.markdown +22 -0
- data/public/noty/demo/allLayouts.html +91 -0
- data/public/noty/demo/allTypes.html +86 -0
- data/public/noty/demo/api.html +103 -0
- data/public/noty/demo/buttons.css +320 -0
- data/public/noty/demo/consumingAlert.html +78 -0
- data/public/noty/demo/customContainer.html +90 -0
- data/public/noty/demo/index.html +66 -0
- data/public/noty/demo/jquery-1.7.2.min.js +4 -0
- data/public/noty/demo/usingMaxVisible.html +104 -0
- data/public/noty/demo/usingWithButtons.html +104 -0
- data/public/noty/demo/usingWithButtons2.html +98 -0
- data/public/noty/demo/usingWithModal.html +87 -0
- data/public/noty/demo/usingWithOldOptions.html +110 -0
- data/public/noty/js/jquery.noty.js +547 -0
- data/public/noty/js/layouts/bottom.js +34 -0
- data/public/noty/js/layouts/bottomCenter.js +41 -0
- data/public/noty/js/layouts/bottomLeft.js +43 -0
- data/public/noty/js/layouts/bottomRight.js +43 -0
- data/public/noty/js/layouts/center.js +56 -0
- data/public/noty/js/layouts/centerLeft.js +61 -0
- data/public/noty/js/layouts/centerRight.js +61 -0
- data/public/noty/js/layouts/inline.js +31 -0
- data/public/noty/js/layouts/top.js +34 -0
- data/public/noty/js/layouts/topCenter.js +41 -0
- data/public/noty/js/layouts/topLeft.js +43 -0
- data/public/noty/js/layouts/topRight.js +43 -0
- data/public/noty/js/promise.js +432 -0
- data/public/noty/js/themes/default.js +156 -0
- data/views/apply.erb +134 -0
- data/views/base.erb +25 -0
- data/views/list.erb +41 -0
- data/views/review.erb +141 -0
- data/views/show.erb +96 -0
- data/views/view.erb +7 -0
- metadata +294 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
module Ocp::Registry
|
2
|
+
|
3
|
+
class CloudManager
|
4
|
+
|
5
|
+
class Openstack
|
6
|
+
|
7
|
+
module KeystoneHelper
|
8
|
+
#{
|
9
|
+
# "name": "ACME corp",
|
10
|
+
# "description": "A description ...",
|
11
|
+
# "enabled": true
|
12
|
+
#}
|
13
|
+
def create_tenant(name, description, enabled = true)
|
14
|
+
with_openstack do
|
15
|
+
keystone.tenants.create( :name => name ,
|
16
|
+
:description => description ,
|
17
|
+
:enabled => enabled )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#{
|
22
|
+
# "username": "jqsmith",
|
23
|
+
# "email": "john.smith@example.org",
|
24
|
+
# "enabled": true,
|
25
|
+
# "OS-KSADM:password": "secrete"
|
26
|
+
#}
|
27
|
+
def create_user(name, tenant_id, password, email = '')
|
28
|
+
with_openstack do
|
29
|
+
keystone.users.create( :name => name,
|
30
|
+
:tenant_id => tenant_id,
|
31
|
+
:password => password,
|
32
|
+
:email => email)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_tenant_by_name(name)
|
37
|
+
with_openstack { keystone.tenants.find {|tenant| tenant.name == name} }
|
38
|
+
end
|
39
|
+
|
40
|
+
def tenant_add_user_with_role(tenant, user_id, role_id)
|
41
|
+
with_openstack { tenant.grant_user_role(user_id, role_id) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_role_by_name(name)
|
45
|
+
with_openstack { keystone.roles.find {|role| role.name == name} }
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_user_by_name(name)
|
49
|
+
with_openstack { keystone.users.find {|user| user.name == name} }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Ocp::Registry
|
2
|
+
|
3
|
+
class CloudManager
|
4
|
+
|
5
|
+
class Openstack
|
6
|
+
|
7
|
+
module NovaHelper
|
8
|
+
|
9
|
+
NOVA_QUOTA_FIELDS = ["metadata_items",
|
10
|
+
"cores",
|
11
|
+
"instances",
|
12
|
+
"injected_files",
|
13
|
+
"injected_file_content_bytes",
|
14
|
+
"ram",
|
15
|
+
"floating_ips",
|
16
|
+
"fixed_ips",
|
17
|
+
"security_groups",
|
18
|
+
"security_group_rules"]
|
19
|
+
|
20
|
+
def default_compute_quota
|
21
|
+
with_openstack { compute.get_quota_defaults(nil).body["quota_set"] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_compute_quota(tenant_id, hash)
|
25
|
+
with_openstack do
|
26
|
+
settings = Ocp::Registry::Common.hash_filter(hash, NOVA_QUOTA_FIELDS)
|
27
|
+
compute.update_quota(tenant_id,settings).body["quota_set"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
|
2
|
+
module Ocp::Registry
|
3
|
+
|
4
|
+
class CloudManager
|
5
|
+
|
6
|
+
class Openstack < CloudManager
|
7
|
+
|
8
|
+
require 'openstack/cinder_helper'
|
9
|
+
require 'openstack/nova_helper'
|
10
|
+
require 'openstack/keystone_helper'
|
11
|
+
|
12
|
+
include KeystoneHelper
|
13
|
+
include NovaHelper
|
14
|
+
include CinderHelper
|
15
|
+
|
16
|
+
def initialize(cloud_config)
|
17
|
+
validate_options(cloud_config)
|
18
|
+
|
19
|
+
@logger = Ocp::Registry.logger
|
20
|
+
|
21
|
+
@openstack_properties = cloud_config["openstack"]
|
22
|
+
|
23
|
+
unless @openstack_properties["auth_url"].match(/\/tokens$/)
|
24
|
+
@openstack_properties["auth_url"] = @openstack_properties["auth_url"] + "/tokens"
|
25
|
+
end
|
26
|
+
|
27
|
+
@openstack_options = {
|
28
|
+
:provider => "OpenStack",
|
29
|
+
:openstack_auth_url => @openstack_properties["auth_url"],
|
30
|
+
:openstack_username => @openstack_properties["username"],
|
31
|
+
:openstack_api_key => @openstack_properties["api_key"],
|
32
|
+
:openstack_tenant => @openstack_properties["tenant"],
|
33
|
+
:openstack_endpoint_type => @openstack_properties["endpoint_type"]
|
34
|
+
}
|
35
|
+
@default_role_name = cloud_config["default_role"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def logger
|
39
|
+
@logger
|
40
|
+
end
|
41
|
+
|
42
|
+
def compute
|
43
|
+
@compute ||= Fog::Compute.new(@openstack_options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def keystone
|
47
|
+
@keystone ||= Fog::Identity.new(@openstack_options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def volume
|
51
|
+
@volume ||= Fog::Volume.new(@openstack_options)
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_options(cloud_config)
|
55
|
+
unless cloud_config.has_key?("openstack") &&
|
56
|
+
cloud_config["openstack"].is_a?(Hash) &&
|
57
|
+
cloud_config["openstack"]["auth_url"] &&
|
58
|
+
cloud_config["openstack"]["username"] &&
|
59
|
+
cloud_config["openstack"]["api_key"] &&
|
60
|
+
cloud_config["openstack"]["tenant"] &&
|
61
|
+
cloud_config["default_role"]
|
62
|
+
raise ConfigError, "Invalid OpenStack configuration parameters"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_tenant_quota(tenant_id, settings={})
|
67
|
+
result = nil
|
68
|
+
with_openstack do
|
69
|
+
compute_quota = set_compute_quota(tenant_id, settings)
|
70
|
+
volume_quota = set_volume_quota(tenant_id, settings)
|
71
|
+
result = compute_quota.merge (volume_quota) if (compute_quota && volume_quota)
|
72
|
+
end
|
73
|
+
cloud_error "Quota for #{tenant_id} has not been set" unless result
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
def default_quota
|
78
|
+
return @default_quota if @default_quota
|
79
|
+
with_openstack do
|
80
|
+
compute_quota = default_compute_quota
|
81
|
+
volume_quota = default_volume_quota
|
82
|
+
@default_quota = compute_quota.merge (volume_quota)
|
83
|
+
end
|
84
|
+
cloud_error "Default Quota is not found" unless @default_quota
|
85
|
+
@default_quota
|
86
|
+
end
|
87
|
+
|
88
|
+
def default_role
|
89
|
+
return @default_role if @default_role
|
90
|
+
with_openstack do
|
91
|
+
@default_role ||= get_role_by_name(@default_role_name)
|
92
|
+
end
|
93
|
+
cloud_error "Default Role [#{cloud_config["default_role"]}] is not found" unless @default_role
|
94
|
+
@logger.info("Default Role #{@default_role.name} - #{@default_role.id}")
|
95
|
+
@default_role
|
96
|
+
end
|
97
|
+
|
98
|
+
def with_openstack
|
99
|
+
retried = false
|
100
|
+
begin
|
101
|
+
yield
|
102
|
+
rescue Excon::Errors::Unauthorized => e
|
103
|
+
unless retried
|
104
|
+
retried = true
|
105
|
+
@compute = nil
|
106
|
+
@volume = nil
|
107
|
+
@keystone = nil
|
108
|
+
retry
|
109
|
+
end
|
110
|
+
cloud_error "Unable to connect to OpenStack API: #{e.message}", e
|
111
|
+
rescue Excon::Errors::InternalServerError => e
|
112
|
+
cloud_error "OpenStack API Internal Server error. Check debug log for details.", e
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def cloud_error(message, exception = nil)
|
117
|
+
@logger.error(message) if @logger
|
118
|
+
@logger.error(exception) if @logger && exception
|
119
|
+
raise Ocp::Registry::CloudError, message
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Ocp::Registry::Common
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def uuid
|
6
|
+
SecureRandom.uuid
|
7
|
+
end
|
8
|
+
|
9
|
+
def gen_password
|
10
|
+
SecureRandom.base64
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_email(email)
|
14
|
+
return unless email =~ /[a-z0-9_.-]+@[a-z0-9-]+\.[a-z.]+/
|
15
|
+
email =~ /([a-z0-9_.-]+)@([a-z0-9-]+\.[a-z.]+)/
|
16
|
+
{
|
17
|
+
:name => $1 ,
|
18
|
+
:domain => $2
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def hash_filter(hash, fields = [])
|
23
|
+
copy = deep_copy(hash)
|
24
|
+
do_hash_filter(copy, fields)
|
25
|
+
end
|
26
|
+
|
27
|
+
def deep_copy(o)
|
28
|
+
Marshal.load(Marshal.dump(o))
|
29
|
+
end
|
30
|
+
|
31
|
+
def json_merge(a,b,reverse = false)
|
32
|
+
hash_a = Yajl::load a
|
33
|
+
hash_b = Yajl::load b
|
34
|
+
if reverse
|
35
|
+
b.merge a
|
36
|
+
else
|
37
|
+
a.merge b
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def do_hash_filter(hash, fields = [])
|
44
|
+
hash.keep_if do |k,v|
|
45
|
+
if v.is_a? Hash
|
46
|
+
do_hash_filter(v, fields)
|
47
|
+
!v.empty?
|
48
|
+
else
|
49
|
+
fields.include? k
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
module Ocp::Registry
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
attr_accessor :logger
|
7
|
+
attr_accessor :base_url
|
8
|
+
attr_accessor :http_port
|
9
|
+
attr_accessor :http_user
|
10
|
+
attr_accessor :http_password
|
11
|
+
attr_accessor :db
|
12
|
+
attr_accessor :application_manager
|
13
|
+
attr_accessor :cloud_login_url
|
14
|
+
|
15
|
+
def configure(config)
|
16
|
+
validate_config(config)
|
17
|
+
|
18
|
+
@logger ||= Logger.new(config["logfile"] || STDOUT)
|
19
|
+
if config["loglevel"].kind_of?(String)
|
20
|
+
@logger.level = Logger.const_get(config["loglevel"].upcase)
|
21
|
+
end
|
22
|
+
|
23
|
+
@base_url = config["http"]["base_url"] || "127.0.0.1"
|
24
|
+
@http_port = config["http"]["port"]
|
25
|
+
@http_user = config["http"]["user"]
|
26
|
+
@http_password = config["http"]["password"]
|
27
|
+
|
28
|
+
@db = connect_db(config["db"])
|
29
|
+
|
30
|
+
migrate_db if @db
|
31
|
+
|
32
|
+
@cloud_login_url = config["cloud"]["login_url"]
|
33
|
+
|
34
|
+
plugin = config["cloud"]["plugin"]
|
35
|
+
begin
|
36
|
+
require "ocp_registry/cloud_manager/#{plugin}"
|
37
|
+
rescue LoadError
|
38
|
+
raise ConfigError, "Could not find Provider Plugin: #{plugin}"
|
39
|
+
end
|
40
|
+
@cloud_manager = Ocp::Registry::CloudManager.const_get(plugin.capitalize).new(config["cloud"])
|
41
|
+
|
42
|
+
@mail_client = init_mail_client(config["mail"]) if config["mail"]
|
43
|
+
|
44
|
+
@application_manager = Ocp::Registry::ApplicationManager.new(@cloud_manager,@mail_client)
|
45
|
+
end
|
46
|
+
|
47
|
+
def init_mail_client(mail_config)
|
48
|
+
require "ocp_registry/mail_client"
|
49
|
+
MailClient.new(mail_config)
|
50
|
+
end
|
51
|
+
|
52
|
+
def migrate_db
|
53
|
+
Sequel.extension :migration
|
54
|
+
Sequel::Migrator.apply(@db,File.expand_path('./lib/ocp_registry/db'))
|
55
|
+
end
|
56
|
+
|
57
|
+
def connect_db(db_config)
|
58
|
+
connection_options = db_config.delete('connection_options') {{}}
|
59
|
+
db_config.delete_if { |_, v| v.to_s.empty? }
|
60
|
+
db_config = db_config.merge(connection_options)
|
61
|
+
|
62
|
+
db = Sequel.connect(db_config)
|
63
|
+
if logger
|
64
|
+
db.logger = @logger
|
65
|
+
db.sql_log_level = :debug
|
66
|
+
end
|
67
|
+
|
68
|
+
db
|
69
|
+
end
|
70
|
+
|
71
|
+
def validate_config(config)
|
72
|
+
unless config.is_a?(Hash)
|
73
|
+
raise ConfigError, "Invalid config format, Hash expected, " \
|
74
|
+
"#{config.class} given"
|
75
|
+
end
|
76
|
+
|
77
|
+
unless config.has_key?("http") && config["http"].is_a?(Hash)
|
78
|
+
raise ConfigError, "HTTP configuration is missing from config file"
|
79
|
+
end
|
80
|
+
|
81
|
+
unless config.has_key?("db") && config["db"].is_a?(Hash)
|
82
|
+
raise ConfigError, "Database configuration is missing from config file"
|
83
|
+
end
|
84
|
+
|
85
|
+
unless config.has_key?("cloud") && config["cloud"].is_a?(Hash)
|
86
|
+
raise ConfigError, "Cloud configuration is missing from config file"
|
87
|
+
end
|
88
|
+
|
89
|
+
if config["cloud"]["plugin"].nil?
|
90
|
+
raise ConfigError, "Cloud plugin is missing from config file"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
Sequel.migration do
|
3
|
+
change do
|
4
|
+
create_table(:registry_applications) do
|
5
|
+
primary_key :id ,:auto_increment => false, :type => String
|
6
|
+
String :email , :null => false
|
7
|
+
String :project , :null => false
|
8
|
+
String :description , :text => true
|
9
|
+
String :state , :null => false , :default => 'PENDING'
|
10
|
+
String :created_at , :null => false
|
11
|
+
String :updated_at
|
12
|
+
String :comments , :text => true
|
13
|
+
String :settings , :null => false , :text => true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Ocp::Registry
|
2
|
+
|
3
|
+
class Error < StandardError
|
4
|
+
def self.code(code = 500)
|
5
|
+
define_method(:code) { code }
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class FatalError < Error; end
|
10
|
+
|
11
|
+
class ConfigError < Error; end
|
12
|
+
class ConnectionError < Error; end
|
13
|
+
|
14
|
+
class CloudError < Error ; end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Ocp::Registry
|
2
|
+
class MailClient
|
3
|
+
|
4
|
+
require "net/smtp"
|
5
|
+
require "thread"
|
6
|
+
|
7
|
+
DEFAULT_WORKER = 1
|
8
|
+
DEFAULT_PORT = '25'
|
9
|
+
DEFAULT_HELO = 'ocp.com'
|
10
|
+
TEMPLATES_PATH = 'mail_template'
|
11
|
+
DEFAULT_FROM = 'registry@ocp.com'
|
12
|
+
DEFAULT_TLS = false
|
13
|
+
DEFAULT_ADMIN_EMAIL = 'admin@ocp.com'
|
14
|
+
|
15
|
+
def initialize(mail_config)
|
16
|
+
validate_opinions(mail_config)
|
17
|
+
|
18
|
+
@logger = Ocp::Registry.logger
|
19
|
+
|
20
|
+
@worker = mail_config["worker"] || DEFAULT_WORKER
|
21
|
+
@enable_tls = mail_config["enable_tls"] || DEFAULT_TLS
|
22
|
+
|
23
|
+
@mail_opinions = {
|
24
|
+
:address => mail_config["smtp_server"] ,
|
25
|
+
:port => mail_config["port"] || DEFAULT_PORT ,
|
26
|
+
:helo => mail_config["helo"] || DEFAULT_HELO ,
|
27
|
+
:user => mail_config["username"] || nil ,
|
28
|
+
:secret => mail_config["password"] || nil ,
|
29
|
+
:authtype => mail_config["authentication"] || nil
|
30
|
+
}
|
31
|
+
|
32
|
+
@admin_emails = mail_config["admin_emails"] || DEFAULT_ADMIN_EMAIL
|
33
|
+
|
34
|
+
@mail_queue = Queue.new
|
35
|
+
|
36
|
+
setup_senders
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def admin_emails
|
41
|
+
@admin_emails
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_mail(mail_info)
|
45
|
+
mail_info.merge!({ :from => DEFAULT_FROM })
|
46
|
+
@mail_queue << mail_info if mail_validated?(mail_info)
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_opinions(mail_config)
|
50
|
+
unless mail_config["smtp_server"] && mail_config["admin_emails"]
|
51
|
+
raise ConfigError, "Invalid Mail configuration"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def mail_validated?(mail_info)
|
56
|
+
unless mail_info[:from] && mail_info[:to] && mail_info[:template] && has_template?(mail_info[:template])
|
57
|
+
@logger.waring "Mail is ignored because less of necessary fields "
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def has_template?(template)
|
64
|
+
File.exists? File.expand_path("#{TEMPLATES_PATH}/#{template}.erb")
|
65
|
+
end
|
66
|
+
|
67
|
+
def prepare_message(mail)
|
68
|
+
template = mail.delete(:template)
|
69
|
+
template = File.read(File.expand_path("#{TEMPLATES_PATH}/#{template}.erb"))
|
70
|
+
@logger.debug "Starting prepare message for mail - #{mail.to_s}"
|
71
|
+
begin
|
72
|
+
info = mail[:msg]
|
73
|
+
message = ERB.new(template).result binding
|
74
|
+
rescue Exception => e
|
75
|
+
@logger.error "Load email template failed - #{e.message}"
|
76
|
+
@logger.debug(e.backtrace.join("\n"))
|
77
|
+
end
|
78
|
+
return message , mail[:from] , mail[:to]
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# Here we use multi-thread to realize a provider-consumer mode with a block-queue
|
84
|
+
# TODO: Realize with Fiber
|
85
|
+
def setup_senders
|
86
|
+
@worker.times do |index|
|
87
|
+
|
88
|
+
thread = Thread.new { create_sender }
|
89
|
+
thread.run
|
90
|
+
|
91
|
+
@logger.info("Mail sender thread #{index} is running ")
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def create_sender
|
99
|
+
loop do
|
100
|
+
mail = @mail_queue.pop
|
101
|
+
begin
|
102
|
+
if @enable_tls
|
103
|
+
require "tlsmail"
|
104
|
+
Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
|
105
|
+
end
|
106
|
+
@logger.info("Starting SMTP with opinions #{@mail_opinions}")
|
107
|
+
Net::SMTP.start(@mail_opinions[:address] ,
|
108
|
+
@mail_opinions[:port] ,
|
109
|
+
@mail_opinions[:helo] ,
|
110
|
+
@mail_opinions[:user] ,
|
111
|
+
@mail_opinions[:secret] ,
|
112
|
+
@mail_opinions[:authtype]) do |smtp|
|
113
|
+
until mail.nil? do
|
114
|
+
msg, from, to = prepare_message(mail)
|
115
|
+
smtp.send_message(msg, from, to)
|
116
|
+
@logger.debug("Mail is sent with message \n#{msg}")
|
117
|
+
begin
|
118
|
+
mail = @mail_queue.pop(:non_block => true )
|
119
|
+
rescue ThreadError => e
|
120
|
+
mail = nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
rescue Net::SMTPAuthenticationError => e
|
125
|
+
@logger.error("Mail server authentication failed - #{e.message}", e)
|
126
|
+
@logger.debug(e.backtrace.join("\n"))
|
127
|
+
rescue Net::SMTPError => e
|
128
|
+
@logger.error("Mail is not sent because of SMTP error - #{e.message}")
|
129
|
+
@logger.debug(e.backtrace.join("\n"))
|
130
|
+
rescue Exception => e
|
131
|
+
@logger.error(e.message)
|
132
|
+
@logger.debug(e.backtrace.join("\n"))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|