manageiq-appliance_console 5.5.0 → 7.0.1
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +24 -25
- data/.rspec_ci +2 -0
- data/.rubocop.yml +3 -3
- data/.rubocop_cc.yml +3 -4
- data/.rubocop_local.yml +1 -1
- data/.travis.yml +4 -3
- data/Gemfile +1 -3
- data/README.md +1 -2
- data/Rakefile +20 -1
- data/bin/appliance_console +30 -6
- data/lib/manageiq/appliance_console/certificate_authority.rb +1 -1
- data/lib/manageiq/appliance_console/cli.rb +166 -70
- data/lib/manageiq/appliance_console/database_admin.rb +35 -206
- data/lib/manageiq/appliance_console/database_configuration.rb +10 -2
- data/lib/manageiq/appliance_console/database_replication.rb +1 -1
- data/lib/manageiq/appliance_console/database_replication_standby.rb +1 -1
- data/lib/manageiq/appliance_console/external_auth_options.rb +3 -13
- data/lib/manageiq/appliance_console/internal_database_configuration.rb +4 -12
- data/lib/manageiq/appliance_console/key_configuration.rb +8 -1
- data/lib/manageiq/appliance_console/logfile_configuration.rb +2 -2
- data/lib/manageiq/appliance_console/manageiq_user_mixin.rb +15 -0
- data/lib/manageiq/appliance_console/message_configuration.rb +205 -0
- data/lib/manageiq/appliance_console/message_configuration_client.rb +98 -0
- data/lib/manageiq/appliance_console/message_configuration_server.rb +321 -0
- data/lib/manageiq/appliance_console/oidc_authentication.rb +27 -1
- data/lib/manageiq/appliance_console/postgres_admin.rb +412 -0
- data/lib/manageiq/appliance_console/utilities.rb +61 -2
- data/lib/manageiq/appliance_console/version.rb +1 -1
- data/lib/manageiq-appliance_console.rb +2 -6
- data/locales/appliance/en.yml +0 -16
- data/manageiq-appliance_console.gemspec +4 -3
- metadata +54 -24
- data/lib/manageiq/appliance_console/messaging_configuration.rb +0 -92
@@ -4,6 +4,8 @@ require 'net/scp'
|
|
4
4
|
require 'active_support/all'
|
5
5
|
require 'manageiq-password'
|
6
6
|
|
7
|
+
require_relative './manageiq_user_mixin'
|
8
|
+
|
7
9
|
module ManageIQ
|
8
10
|
module ApplianceConsole
|
9
11
|
CERT_DIR = ENV['KEY_ROOT'] || ManageIQ::ApplianceConsole::RAILS_ROOT.join("certs")
|
@@ -11,6 +13,8 @@ module ApplianceConsole
|
|
11
13
|
NEW_KEY_FILE = "#{KEY_FILE}.tmp".freeze
|
12
14
|
|
13
15
|
class KeyConfiguration
|
16
|
+
include ManageIQ::ApplianceConsole::ManageiqUserMixin
|
17
|
+
|
14
18
|
attr_accessor :host, :login, :password, :key_path, :action, :force
|
15
19
|
|
16
20
|
def initialize(options = {})
|
@@ -89,7 +93,9 @@ module ApplianceConsole
|
|
89
93
|
end
|
90
94
|
|
91
95
|
def create_key
|
92
|
-
ManageIQ::Password.generate_symmetric(NEW_KEY_FILE)
|
96
|
+
return unless !!ManageIQ::Password.generate_symmetric(NEW_KEY_FILE)
|
97
|
+
|
98
|
+
File.chown(manageiq_uid, manageiq_gid, NEW_KEY_FILE)
|
93
99
|
end
|
94
100
|
|
95
101
|
def fetch_key
|
@@ -97,6 +103,7 @@ module ApplianceConsole
|
|
97
103
|
Net::SCP.start(host, login, :password => password) do |scp|
|
98
104
|
scp.download!(key_path, NEW_KEY_FILE)
|
99
105
|
end
|
106
|
+
File.chown(manageiq_uid, manageiq_gid, NEW_KEY_FILE)
|
100
107
|
File.exist?(NEW_KEY_FILE)
|
101
108
|
rescue => e
|
102
109
|
say("Failed to fetch key: #{e.message}")
|
@@ -1,7 +1,7 @@
|
|
1
|
+
require "manageiq/appliance_console/utilities"
|
1
2
|
require 'linux_admin'
|
2
3
|
require 'pathname'
|
3
4
|
require 'fileutils'
|
4
|
-
require 'util/miq-system.rb'
|
5
5
|
|
6
6
|
module ManageIQ
|
7
7
|
module ApplianceConsole
|
@@ -18,7 +18,7 @@ module ApplianceConsole
|
|
18
18
|
self.disk = config[:disk]
|
19
19
|
self.new_logrotate_count = nil
|
20
20
|
|
21
|
-
self.size =
|
21
|
+
self.size = Utilities.disk_usage(LOGFILE_DIRECTORY)[0][:total_bytes]
|
22
22
|
self.current_logrotate_count = /rotate\s+(\d+)/.match(File.read(MIQ_LOGS_CONF))[1]
|
23
23
|
self.evm_was_running = LinuxAdmin::Service.new("evmserverd").running?
|
24
24
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ManageIQ
|
2
|
+
module ApplianceConsole
|
3
|
+
module ManageiqUserMixin
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def manageiq_uid
|
7
|
+
@manageiq_uid ||= Process::UID.from_name("manageiq")
|
8
|
+
end
|
9
|
+
|
10
|
+
def manageiq_gid
|
11
|
+
@manageiq_gid ||= Process::GID.from_name("manageiq")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
require_relative './manageiq_user_mixin'
|
5
|
+
|
6
|
+
module ManageIQ
|
7
|
+
module ApplianceConsole
|
8
|
+
class MessageConfiguration
|
9
|
+
include ManageIQ::ApplianceConsole::ManageiqUserMixin
|
10
|
+
|
11
|
+
attr_reader :message_keystore_username, :message_keystore_password,
|
12
|
+
:message_server_host, :message_server_port,
|
13
|
+
:miq_config_dir_path, :config_dir_path, :sample_config_dir_path,
|
14
|
+
:client_properties_path,
|
15
|
+
:keystore_dir_path, :truststore_path, :keystore_path,
|
16
|
+
:messaging_yaml_sample_path, :messaging_yaml_path,
|
17
|
+
:ca_cert_path
|
18
|
+
|
19
|
+
BASE_DIR = "/opt/kafka".freeze
|
20
|
+
LOGS_DIR = "#{BASE_DIR}/logs".freeze
|
21
|
+
CONFIG_DIR = "#{BASE_DIR}/config".freeze
|
22
|
+
SAMPLE_CONFIG_DIR = "#{BASE_DIR}/config-sample".freeze
|
23
|
+
MIQ_CONFIG_DIR = ManageIQ::ApplianceConsole::RAILS_ROOT.join("config").freeze
|
24
|
+
|
25
|
+
def initialize(options = {})
|
26
|
+
@message_server_port = options[:message_server_port] || 9093
|
27
|
+
@message_keystore_username = options[:message_keystore_username] || "admin"
|
28
|
+
@message_keystore_password = options[:message_keystore_password]
|
29
|
+
|
30
|
+
@miq_config_dir_path = Pathname.new(MIQ_CONFIG_DIR)
|
31
|
+
@config_dir_path = Pathname.new(CONFIG_DIR)
|
32
|
+
@sample_config_dir_path = Pathname.new(SAMPLE_CONFIG_DIR)
|
33
|
+
|
34
|
+
@client_properties_path = config_dir_path.join("client.properties")
|
35
|
+
@keystore_dir_path = config_dir_path.join("keystore")
|
36
|
+
@truststore_path = keystore_dir_path.join("truststore.jks")
|
37
|
+
@keystore_path = keystore_dir_path.join("keystore.jks")
|
38
|
+
|
39
|
+
@messaging_yaml_sample_path = miq_config_dir_path.join("messaging.kafka.yml")
|
40
|
+
@messaging_yaml_path = miq_config_dir_path.join("messaging.yml")
|
41
|
+
@ca_cert_path = keystore_dir_path.join("ca-cert")
|
42
|
+
end
|
43
|
+
|
44
|
+
def already_configured?
|
45
|
+
installed_file_found = false
|
46
|
+
installed_files.each do |f|
|
47
|
+
if File.exist?(f)
|
48
|
+
installed_file_found = true
|
49
|
+
say("Installed file #{f} found.")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
installed_file_found
|
53
|
+
end
|
54
|
+
|
55
|
+
def ask_questions
|
56
|
+
return false unless valid_environment?
|
57
|
+
|
58
|
+
ask_for_parameters
|
59
|
+
show_parameters
|
60
|
+
return false unless agree("\nProceed? (Y/N): ")
|
61
|
+
|
62
|
+
return false unless host_reachable?(message_server_host, "Message Server Host:")
|
63
|
+
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_client_properties
|
68
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
69
|
+
|
70
|
+
return if file_found?(client_properties_path)
|
71
|
+
|
72
|
+
algorithm = message_server_host.ipaddress? ? "" : "HTTPS"
|
73
|
+
protocol = secure? ? "SASL_SSL" : "PLAINTEXT"
|
74
|
+
content = secure? ? secure_client_properties_content(algorithm, protocol) : unsecure_client_properties_content(algorithm, protocol)
|
75
|
+
|
76
|
+
File.write(client_properties_path, content)
|
77
|
+
end
|
78
|
+
|
79
|
+
def secure_client_properties_content(algorithm, protocol)
|
80
|
+
secure_content = <<~CLIENT_PROPERTIES
|
81
|
+
ssl.truststore.location=#{truststore_path}
|
82
|
+
ssl.truststore.password=#{message_keystore_password}
|
83
|
+
CLIENT_PROPERTIES
|
84
|
+
|
85
|
+
unsecure_client_properties_content(algorithm, protocol) + secure_content
|
86
|
+
end
|
87
|
+
|
88
|
+
def unsecure_client_properties_content(algorithm, protocol)
|
89
|
+
<<~CLIENT_PROPERTIES
|
90
|
+
ssl.endpoint.identification.algorithm=#{algorithm}
|
91
|
+
|
92
|
+
sasl.mechanism=PLAIN
|
93
|
+
security.protocol=#{protocol}
|
94
|
+
sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \\
|
95
|
+
username=#{message_keystore_username} \\
|
96
|
+
password=#{message_keystore_password} ;
|
97
|
+
CLIENT_PROPERTIES
|
98
|
+
end
|
99
|
+
|
100
|
+
def configure_messaging_yaml
|
101
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
102
|
+
|
103
|
+
return if file_found?(messaging_yaml_path)
|
104
|
+
|
105
|
+
messaging_yaml = YAML.load_file(messaging_yaml_sample_path)
|
106
|
+
|
107
|
+
messaging_yaml["production"].delete("username")
|
108
|
+
messaging_yaml["production"].delete("password")
|
109
|
+
|
110
|
+
messaging_yaml["production"]["hostname"] = message_server_host
|
111
|
+
messaging_yaml["production"]["port"] = message_server_port
|
112
|
+
messaging_yaml["production"]["sasl.mechanism"] = "PLAIN"
|
113
|
+
messaging_yaml["production"]["sasl.username"] = message_keystore_username
|
114
|
+
messaging_yaml["production"]["sasl.password"] = ManageIQ::Password.try_encrypt(message_keystore_password)
|
115
|
+
|
116
|
+
if secure?
|
117
|
+
messaging_yaml["production"]["security.protocol"] = "SASL_SSL"
|
118
|
+
messaging_yaml["production"]["ssl.ca.location"] = ca_cert_path.to_path
|
119
|
+
else
|
120
|
+
messaging_yaml["production"]["security.protocol"] = "PLAINTEXT"
|
121
|
+
end
|
122
|
+
|
123
|
+
File.open(messaging_yaml_path, "w") do |f|
|
124
|
+
f.write(messaging_yaml.to_yaml)
|
125
|
+
f.chown(manageiq_uid, manageiq_gid)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def remove_installed_files
|
130
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
131
|
+
|
132
|
+
installed_files.each { |f| FileUtils.rm_rf(f) }
|
133
|
+
end
|
134
|
+
|
135
|
+
def valid_environment?
|
136
|
+
if already_configured?
|
137
|
+
unconfigure if agree("\nAlready configured on this Appliance, Un-Configure first? (Y/N): ")
|
138
|
+
return false unless agree("\nProceed with Configuration? (Y/N): ")
|
139
|
+
end
|
140
|
+
true
|
141
|
+
end
|
142
|
+
|
143
|
+
def file_found?(path)
|
144
|
+
return false unless File.exist?(path)
|
145
|
+
|
146
|
+
say("\tWARNING: #{path} already exists. Taking no action.")
|
147
|
+
true
|
148
|
+
end
|
149
|
+
|
150
|
+
def files_found?(path_list)
|
151
|
+
return false unless path_list.all? { |path| File.exist?(path) }
|
152
|
+
|
153
|
+
path_list.each { |path| file_found?(path) }
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
def file_contains?(path, content)
|
158
|
+
return false unless File.exist?(path)
|
159
|
+
|
160
|
+
content.split("\n").each do |l|
|
161
|
+
l.gsub!("/", "\\/")
|
162
|
+
l.gsub!(/password=.*$/, "password=") # Remove the password as it can have special characters that grep can not match.
|
163
|
+
return false unless File.foreach(path).grep(/#{l}/).any?
|
164
|
+
end
|
165
|
+
|
166
|
+
say("Content already exists in #{path}. Taking no action.")
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
def host_reachable?(host, what)
|
171
|
+
require 'net/ping'
|
172
|
+
say("Checking connectivity to #{host} ... ")
|
173
|
+
unless Net::Ping::External.new(host).ping
|
174
|
+
say("Failed.\nCould not connect to #{host},")
|
175
|
+
say("the #{what} must be reachable by name.")
|
176
|
+
return false
|
177
|
+
end
|
178
|
+
say("Succeeded.")
|
179
|
+
true
|
180
|
+
end
|
181
|
+
|
182
|
+
def configure_messaging_type(value)
|
183
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
184
|
+
|
185
|
+
ManageIQ::ApplianceConsole::Utilities.rake_run!("evm:settings:set", ["/prototype/messaging_type=#{value}"])
|
186
|
+
end
|
187
|
+
|
188
|
+
def restart_evmserverd
|
189
|
+
say("Restart evmserverd if it is running...")
|
190
|
+
evmserverd_service = LinuxAdmin::Service.new("evmserverd")
|
191
|
+
evmserverd_service.restart if evmserverd_service.running?
|
192
|
+
end
|
193
|
+
|
194
|
+
def unconfigure
|
195
|
+
configure_messaging_type("miq_queue") # Settings.prototype.messaging_type = 'miq_queue'
|
196
|
+
restart_evmserverd
|
197
|
+
remove_installed_files
|
198
|
+
end
|
199
|
+
|
200
|
+
def secure?
|
201
|
+
message_server_port == 9_093
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "awesome_spawn"
|
2
|
+
require "fileutils"
|
3
|
+
require "linux_admin"
|
4
|
+
require 'net/scp'
|
5
|
+
require "manageiq/appliance_console/message_configuration"
|
6
|
+
|
7
|
+
module ManageIQ
|
8
|
+
module ApplianceConsole
|
9
|
+
class MessageClientConfiguration < MessageConfiguration
|
10
|
+
attr_reader :message_server_password, :message_server_username, :installed_files,
|
11
|
+
:message_truststore_path_src, :message_ca_cert_path_src
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
super(options)
|
15
|
+
|
16
|
+
@message_server_host = options[:message_server_host]
|
17
|
+
@message_server_username = options[:message_server_usernamed] || "root"
|
18
|
+
@message_server_password = options[:message_server_password]
|
19
|
+
|
20
|
+
@message_truststore_path_src = options[:message_truststore_path_src] || truststore_path
|
21
|
+
@message_ca_cert_path_src = options[:message_ca_cert_path_src] || ca_cert_path
|
22
|
+
|
23
|
+
@installed_files = [client_properties_path, messaging_yaml_path, truststore_path]
|
24
|
+
end
|
25
|
+
|
26
|
+
def configure
|
27
|
+
begin
|
28
|
+
MessageServerConfiguration.new.unconfigure if MessageServerConfiguration.configured?
|
29
|
+
configure_messaging_yaml # Set up the local message client in case EVM is actually running on this, Message Server
|
30
|
+
create_client_properties # Create the client.properties configuration fle
|
31
|
+
fetch_truststore_from_server # Fetch the Java Keystore from the Kafka Server
|
32
|
+
configure_messaging_type("kafka") # Settings.prototype.messaging_type = 'kafka'
|
33
|
+
restart_evmserverd
|
34
|
+
rescue AwesomeSpawn::CommandResultError => e
|
35
|
+
say(e.result.output)
|
36
|
+
say(e.result.error)
|
37
|
+
say("")
|
38
|
+
say("Failed to Configure the Message Client- #{e}")
|
39
|
+
return false
|
40
|
+
rescue => e
|
41
|
+
say("Failed to Configure the Message Client- #{e}")
|
42
|
+
return false
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def ask_for_parameters
|
48
|
+
say("\nMessage Client Parameters:\n\n")
|
49
|
+
|
50
|
+
@message_server_host = ask_for_string("Message Server Hostname or IP address")
|
51
|
+
@message_server_port = ask_for_integer("Message Server Port number", (1..65_535), 9_093).to_i
|
52
|
+
@message_server_username = ask_for_string("Message Server Username", message_server_username)
|
53
|
+
@message_server_password = ask_for_password("Message Server Password")
|
54
|
+
@message_truststore_path_src = ask_for_string("Message Server Truststore Path", truststore_path)
|
55
|
+
@message_ca_cert_path_src = ask_for_string("Message Server CA Cert Path", ca_cert_path)
|
56
|
+
@message_keystore_username = ask_for_string("Message Keystore Username", message_keystore_username) if secure?
|
57
|
+
@message_keystore_password = ask_for_password("Message Keystore Password") if secure?
|
58
|
+
end
|
59
|
+
|
60
|
+
def show_parameters
|
61
|
+
say("\nMessage Client Configuration:\n")
|
62
|
+
say("Message Client Details:\n")
|
63
|
+
say(" Message Server Hostname: #{message_server_host}\n")
|
64
|
+
say(" Message Server Username: #{message_server_username}\n")
|
65
|
+
say(" Message Keystore Username: #{message_keystore_username}\n")
|
66
|
+
end
|
67
|
+
|
68
|
+
def fetch_truststore_from_server
|
69
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
70
|
+
|
71
|
+
fetch_from_server(message_truststore_path_src, truststore_path)
|
72
|
+
end
|
73
|
+
|
74
|
+
def fetch_ca_cert_from_server
|
75
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
76
|
+
|
77
|
+
fetch_from_server(message_ca_cert_path_src, ca_cert_path)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def fetch_from_server(src_file, dst_file)
|
83
|
+
return if file_found?(dst_file)
|
84
|
+
|
85
|
+
FileUtils.mkdir_p(dst_file.dirname) unless dst_file.dirname.directory?
|
86
|
+
|
87
|
+
Net::SCP.start(message_server_host, message_server_username, :password => message_server_password) do |scp|
|
88
|
+
scp.download!(src_file, dst_file)
|
89
|
+
end
|
90
|
+
|
91
|
+
File.exist?(dst_file)
|
92
|
+
rescue => e
|
93
|
+
say("Failed to fetch #{src_file} from server: #{e.message}")
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,321 @@
|
|
1
|
+
require "awesome_spawn"
|
2
|
+
require "fileutils"
|
3
|
+
require "linux_admin"
|
4
|
+
require "manageiq/appliance_console/message_configuration"
|
5
|
+
|
6
|
+
module ManageIQ
|
7
|
+
module ApplianceConsole
|
8
|
+
class MessageServerConfiguration < MessageConfiguration
|
9
|
+
attr_reader :jaas_config_path,
|
10
|
+
:server_properties_path, :server_properties_sample_path,
|
11
|
+
:ca_cert_srl_path, :ca_key_path, :cert_file_path, :cert_signed_path,
|
12
|
+
:keystore_files, :installed_files, :message_persistent_disk
|
13
|
+
|
14
|
+
PERSISTENT_DIRECTORY = Pathname.new("/var/lib/kafka/persistent_data").freeze
|
15
|
+
PERSISTENT_NAME = "kafka_messages".freeze
|
16
|
+
|
17
|
+
def initialize(options = {})
|
18
|
+
super(options)
|
19
|
+
|
20
|
+
@message_server_host = options[:message_server_use_ipaddr] == true ? my_ipaddr : options[:message_server_host] || my_hostname
|
21
|
+
@message_persistent_disk = LinuxAdmin::Disk.new(:path => options[:message_persistent_disk]) unless options[:message_persistent_disk].nil?
|
22
|
+
|
23
|
+
@jaas_config_path = config_dir_path.join("kafka_server_jaas.conf")
|
24
|
+
@server_properties_path = config_dir_path.join("server.properties")
|
25
|
+
@server_properties_sample_path = sample_config_dir_path.join("server.properties")
|
26
|
+
|
27
|
+
@ca_cert_srl_path = keystore_dir_path.join("ca-cert.srl")
|
28
|
+
@ca_key_path = keystore_dir_path.join("ca-key")
|
29
|
+
@cert_file_path = keystore_dir_path.join("cert-file")
|
30
|
+
@cert_signed_path = keystore_dir_path.join("cert-signed")
|
31
|
+
|
32
|
+
@keystore_files = [ca_cert_path, ca_cert_srl_path, ca_key_path, cert_file_path, cert_signed_path, truststore_path, keystore_path]
|
33
|
+
@installed_files = [jaas_config_path, client_properties_path, server_properties_path, messaging_yaml_path, LOGS_DIR] + keystore_files
|
34
|
+
end
|
35
|
+
|
36
|
+
def configure
|
37
|
+
begin
|
38
|
+
configure_persistent_disk # Configure the persistent message store on a different disk
|
39
|
+
create_jaas_config # Create the message server jaas config file
|
40
|
+
create_client_properties # Create the client.properties config
|
41
|
+
create_logs_directory # Create the logs directory:
|
42
|
+
configure_firewall # Open the firewall for message port 9093
|
43
|
+
configure_keystore # Populate the Java Keystore
|
44
|
+
create_server_properties # Update the /opt/message/config/server.properties
|
45
|
+
configure_messaging_yaml # Set up the local message client in case EVM is actually running on this, Message Server
|
46
|
+
configure_messaging_type("kafka") # Settings.prototype.messaging_type = 'kafka'
|
47
|
+
restart_services
|
48
|
+
rescue AwesomeSpawn::CommandResultError => e
|
49
|
+
say(e.result.output)
|
50
|
+
say(e.result.error)
|
51
|
+
say("")
|
52
|
+
say("Failed to Configure the Message Server- #{e}")
|
53
|
+
return false
|
54
|
+
rescue => e
|
55
|
+
say("Failed to Configure the Message Server- #{e}")
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def restart_services
|
62
|
+
say("Starting zookeeper and configure it to start on reboots ...")
|
63
|
+
LinuxAdmin::Service.new("zookeeper").start.enable
|
64
|
+
|
65
|
+
say("Starting kafka and configure it to start on reboots ...")
|
66
|
+
LinuxAdmin::Service.new("kafka").start.enable
|
67
|
+
|
68
|
+
restart_evmserverd
|
69
|
+
end
|
70
|
+
|
71
|
+
def ask_for_parameters
|
72
|
+
say("\nMessage Server Parameters:\n\n")
|
73
|
+
|
74
|
+
@message_server_host = ask_for_string("Message Server Hostname or IP address", message_server_host)
|
75
|
+
@message_keystore_username = ask_for_string("Message Keystore Username", message_keystore_username)
|
76
|
+
@message_keystore_password = ask_for_password("Message Keystore Password")
|
77
|
+
@message_persistent_disk = ask_for_persistent_disk
|
78
|
+
end
|
79
|
+
|
80
|
+
def ask_for_persistent_disk
|
81
|
+
choose_disk if use_new_disk
|
82
|
+
end
|
83
|
+
|
84
|
+
def use_new_disk
|
85
|
+
agree("Configure a new persistent disk volume? (Y/N): ")
|
86
|
+
end
|
87
|
+
|
88
|
+
def choose_disk
|
89
|
+
ask_for_disk("Persistent disk")
|
90
|
+
end
|
91
|
+
|
92
|
+
def show_parameters
|
93
|
+
say("\nMessage Server Configuration:\n")
|
94
|
+
say("Message Server Details:\n")
|
95
|
+
say(" Message Server Hostname: #{message_server_host}\n")
|
96
|
+
say(" Message Keystore Username: #{message_keystore_username}\n")
|
97
|
+
say(" Persistent message disk: #{message_persistent_disk.path}\n") if message_persistent_disk
|
98
|
+
end
|
99
|
+
|
100
|
+
def unconfigure
|
101
|
+
super
|
102
|
+
|
103
|
+
unconfigure_firewall
|
104
|
+
deactivate_services
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.configured?
|
108
|
+
LinuxAdmin::Service.new("kafka").running? ||
|
109
|
+
LinuxAdmin::Service.new("zookeeper").running?
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def my_ipaddr
|
115
|
+
LinuxAdmin::IpAddress.new.address
|
116
|
+
end
|
117
|
+
|
118
|
+
def my_hostname
|
119
|
+
LinuxAdmin::Hosts.new.hostname
|
120
|
+
end
|
121
|
+
|
122
|
+
def configure_persistent_disk
|
123
|
+
return true unless message_persistent_disk
|
124
|
+
|
125
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
126
|
+
|
127
|
+
deactivate_services # Just in case they are running.
|
128
|
+
|
129
|
+
FileUtils.mkdir_p(PERSISTENT_DIRECTORY)
|
130
|
+
LogicalVolumeManagement.new(:disk => message_persistent_disk, :mount_point => PERSISTENT_DIRECTORY, :name => PERSISTENT_NAME).setup
|
131
|
+
FileUtils.chmod(0o755, PERSISTENT_DIRECTORY)
|
132
|
+
FileUtils.chown("kafka", "kafka", PERSISTENT_DIRECTORY)
|
133
|
+
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
137
|
+
def activate_new_persistent_disk
|
138
|
+
return true unless message_persistent_disk
|
139
|
+
|
140
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
141
|
+
|
142
|
+
data = File.read(server_properties_path)
|
143
|
+
data.gsub!(/^log.dirs=.*$/, "log.dirs=#{PERSISTENT_DIRECTORY}")
|
144
|
+
File.write(server_properties_path, data)
|
145
|
+
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
def create_jaas_config
|
150
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
151
|
+
|
152
|
+
content = <<~JAAS
|
153
|
+
KafkaServer {
|
154
|
+
org.apache.kafka.common.security.plain.PlainLoginModule required
|
155
|
+
username=#{message_keystore_username}
|
156
|
+
password=#{message_keystore_password}
|
157
|
+
user_admin=#{message_keystore_password} ;
|
158
|
+
};
|
159
|
+
JAAS
|
160
|
+
|
161
|
+
File.write(jaas_config_path, content) unless file_found?(jaas_config_path)
|
162
|
+
end
|
163
|
+
|
164
|
+
def create_logs_directory
|
165
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
166
|
+
|
167
|
+
return if file_found?(LOGS_DIR)
|
168
|
+
|
169
|
+
FileUtils.mkdir_p(LOGS_DIR)
|
170
|
+
FileUtils.chmod(0o755, LOGS_DIR)
|
171
|
+
FileUtils.chown("kafka", "kafka", LOGS_DIR)
|
172
|
+
end
|
173
|
+
|
174
|
+
def configure_firewall
|
175
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
176
|
+
|
177
|
+
modify_firewall(:add_port)
|
178
|
+
end
|
179
|
+
|
180
|
+
def configure_keystore
|
181
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
182
|
+
|
183
|
+
return if files_found?(keystore_files)
|
184
|
+
|
185
|
+
keystore_params = assemble_keystore_params
|
186
|
+
|
187
|
+
FileUtils.mkdir_p(keystore_dir_path) unless keystore_dir_path.directory?
|
188
|
+
|
189
|
+
# Generte a Java keystore and key pair, creating keystore.jks
|
190
|
+
# :stdin_data provides the -storepass twice to confirm and an extra CR to accept the same password for -keypass
|
191
|
+
AwesomeSpawn.run!("keytool", :params => keystore_params, :stdin_data => "#{message_keystore_password}\n#{message_keystore_password}\n\n")
|
192
|
+
|
193
|
+
# Use openssl to create a new CA cert, creating ca-cert and ca-key
|
194
|
+
AwesomeSpawn.run!("openssl", :env => {"PASSWORD" => message_keystore_password},
|
195
|
+
:params => ["req", "-new", "-x509", {"-keyout" => ca_key_path,
|
196
|
+
"-out" => ca_cert_path,
|
197
|
+
"-days" => 10_000,
|
198
|
+
"-passout" => "env:PASSWORD",
|
199
|
+
"-subj" => '/CN=something'}])
|
200
|
+
|
201
|
+
# Import the CA cert into the trust store, creating truststore.jks
|
202
|
+
# :stdin_data provides the -storepass argument and yes to confirm
|
203
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => truststore_path,
|
204
|
+
"-alias" => "CARoot",
|
205
|
+
"-import" => nil,
|
206
|
+
"-file" => ca_cert_path},
|
207
|
+
:stdin_data => "#{message_keystore_password}\n#{message_keystore_password}\nyes\n")
|
208
|
+
|
209
|
+
# Generate a certificate signing request (CSR) for an existing Java keystore, creating cert-file
|
210
|
+
# :stdin_data provides the -storepass argument
|
211
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => keystore_path,
|
212
|
+
"-alias" => keystore_params["-alias"],
|
213
|
+
"-certreq" => nil,
|
214
|
+
"-file" => cert_file_path},
|
215
|
+
:stdin_data => "#{message_keystore_password}\n")
|
216
|
+
|
217
|
+
# Use openssl to sign the certificate with the "CA" certificate, creating ca-cert.srl and cert-signed
|
218
|
+
AwesomeSpawn.run!("openssl", :env => {"PASSWORD" => message_keystore_password},
|
219
|
+
:params => ["x509", "-req", {"-CA" => ca_cert_path,
|
220
|
+
"-CAkey" => ca_key_path,
|
221
|
+
"-in" => cert_file_path,
|
222
|
+
"-out" => cert_signed_path,
|
223
|
+
"-days" => 10_000,
|
224
|
+
"-CAcreateserial" => nil,
|
225
|
+
"-passin" => "env:PASSWORD"}])
|
226
|
+
|
227
|
+
# Import a root or intermediate CA certificate to an existing Java keystore, updating keystore.jks
|
228
|
+
# :stdin_data provides the -storepass argument and yes to confirm
|
229
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => keystore_path,
|
230
|
+
"-alias" => "CARoot",
|
231
|
+
"-import" => nil,
|
232
|
+
"-file" => ca_cert_path},
|
233
|
+
:stdin_data => "#{message_keystore_password}\nyes\n")
|
234
|
+
|
235
|
+
# Import a signed primary certificate to an existing Java keystore, updating keystore.jks
|
236
|
+
# :stdin_data provides the -storepass argument
|
237
|
+
AwesomeSpawn.run!("keytool", :params => {"-keystore" => keystore_path,
|
238
|
+
"-alias" => keystore_params["-alias"],
|
239
|
+
"-import" => nil,
|
240
|
+
"-file" => cert_signed_path},
|
241
|
+
:stdin_data => "#{message_keystore_password}\n")
|
242
|
+
end
|
243
|
+
|
244
|
+
def create_server_properties
|
245
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
246
|
+
|
247
|
+
if message_server_host.ipaddress?
|
248
|
+
ident_algorithm = ""
|
249
|
+
client_auth = "none"
|
250
|
+
else
|
251
|
+
ident_algorithm = "HTTPS"
|
252
|
+
client_auth = "required"
|
253
|
+
end
|
254
|
+
|
255
|
+
content = <<~SERVER_PROPERTIES
|
256
|
+
|
257
|
+
listeners=SASL_SSL://:#{message_server_port}
|
258
|
+
|
259
|
+
ssl.endpoint.identification.algorithm=#{ident_algorithm}
|
260
|
+
ssl.keystore.location=#{keystore_path}
|
261
|
+
ssl.keystore.password=#{message_keystore_password}
|
262
|
+
ssl.key.password=#{message_keystore_password}
|
263
|
+
|
264
|
+
ssl.truststore.location=#{truststore_path}
|
265
|
+
ssl.truststore.password=#{message_keystore_password}
|
266
|
+
|
267
|
+
ssl.client.auth=#{client_auth}
|
268
|
+
|
269
|
+
sasl.enabled.mechanisms=PLAIN
|
270
|
+
sasl.mechanism.inter.broker.protocol=PLAIN
|
271
|
+
|
272
|
+
security.inter.broker.protocol=SASL_SSL
|
273
|
+
SERVER_PROPERTIES
|
274
|
+
|
275
|
+
return if file_contains?(server_properties_path, content)
|
276
|
+
|
277
|
+
FileUtils.cp(server_properties_sample_path, server_properties_path)
|
278
|
+
File.write(server_properties_path, content, :mode => "a")
|
279
|
+
|
280
|
+
activate_new_persistent_disk
|
281
|
+
end
|
282
|
+
|
283
|
+
def unconfigure_firewall
|
284
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
285
|
+
|
286
|
+
modify_firewall(:remove_port)
|
287
|
+
end
|
288
|
+
|
289
|
+
def deactivate_services
|
290
|
+
say(__method__.to_s.tr("_", " ").titleize)
|
291
|
+
|
292
|
+
LinuxAdmin::Service.new("zookeeper").stop
|
293
|
+
LinuxAdmin::Service.new("kafka").stop
|
294
|
+
end
|
295
|
+
|
296
|
+
def assemble_keystore_params
|
297
|
+
keystore_params = {"-keystore" => keystore_path,
|
298
|
+
"-validity" => 10_000,
|
299
|
+
"-genkey" => nil,
|
300
|
+
"-keyalg" => "RSA"}
|
301
|
+
|
302
|
+
if message_server_host.ipaddress?
|
303
|
+
keystore_params["-alias"] = "localhost"
|
304
|
+
keystore_params["-ext"] = "san=ip:#{message_server_host}"
|
305
|
+
else
|
306
|
+
keystore_params["-alias"] = message_server_host
|
307
|
+
keystore_params["-ext"] = "san=dns:#{message_server_host}"
|
308
|
+
end
|
309
|
+
|
310
|
+
keystore_params["-dname"] = "cn=#{keystore_params["-alias"]}"
|
311
|
+
|
312
|
+
keystore_params
|
313
|
+
end
|
314
|
+
|
315
|
+
def modify_firewall(action)
|
316
|
+
AwesomeSpawn.run!("firewall-cmd", :params => {action => "#{message_server_port}/tcp", :permanent => nil})
|
317
|
+
AwesomeSpawn.run!("firewall-cmd --reload")
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|