manageiq-appliance_console 1.0.0

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +47 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +4 -0
  5. data/.rspec_ci +4 -0
  6. data/.rubocop.yml +4 -0
  7. data/.rubocop_cc.yml +5 -0
  8. data/.rubocop_local.yml +2 -0
  9. data/.travis.yml +19 -0
  10. data/Gemfile +6 -0
  11. data/LICENSE.txt +202 -0
  12. data/README.md +45 -0
  13. data/Rakefile +6 -0
  14. data/bin/appliance_console +661 -0
  15. data/bin/appliance_console_cli +7 -0
  16. data/lib/manageiq-appliance_console.rb +51 -0
  17. data/lib/manageiq/appliance_console/certificate.rb +146 -0
  18. data/lib/manageiq/appliance_console/certificate_authority.rb +140 -0
  19. data/lib/manageiq/appliance_console/cli.rb +363 -0
  20. data/lib/manageiq/appliance_console/database_configuration.rb +286 -0
  21. data/lib/manageiq/appliance_console/database_maintenance.rb +35 -0
  22. data/lib/manageiq/appliance_console/database_maintenance_hourly.rb +58 -0
  23. data/lib/manageiq/appliance_console/database_maintenance_periodic.rb +84 -0
  24. data/lib/manageiq/appliance_console/database_replication.rb +146 -0
  25. data/lib/manageiq/appliance_console/database_replication_primary.rb +59 -0
  26. data/lib/manageiq/appliance_console/database_replication_standby.rb +166 -0
  27. data/lib/manageiq/appliance_console/date_time_configuration.rb +117 -0
  28. data/lib/manageiq/appliance_console/errors.rb +5 -0
  29. data/lib/manageiq/appliance_console/external_auth_options.rb +153 -0
  30. data/lib/manageiq/appliance_console/external_database_configuration.rb +34 -0
  31. data/lib/manageiq/appliance_console/external_httpd_authentication.rb +157 -0
  32. data/lib/manageiq/appliance_console/external_httpd_authentication/external_httpd_configuration.rb +249 -0
  33. data/lib/manageiq/appliance_console/internal_database_configuration.rb +187 -0
  34. data/lib/manageiq/appliance_console/key_configuration.rb +118 -0
  35. data/lib/manageiq/appliance_console/logfile_configuration.rb +117 -0
  36. data/lib/manageiq/appliance_console/logger.rb +23 -0
  37. data/lib/manageiq/appliance_console/logging.rb +102 -0
  38. data/lib/manageiq/appliance_console/logical_volume_management.rb +94 -0
  39. data/lib/manageiq/appliance_console/principal.rb +46 -0
  40. data/lib/manageiq/appliance_console/prompts.rb +211 -0
  41. data/lib/manageiq/appliance_console/scap.rb +53 -0
  42. data/lib/manageiq/appliance_console/temp_storage_configuration.rb +79 -0
  43. data/lib/manageiq/appliance_console/timezone_configuration.rb +58 -0
  44. data/lib/manageiq/appliance_console/utilities.rb +67 -0
  45. data/lib/manageiq/appliance_console/version.rb +5 -0
  46. data/locales/appliance/en.yml +42 -0
  47. data/locales/container/en.yml +30 -0
  48. data/manageiq-appliance_console.gemspec +40 -0
  49. data/zanata.xml +7 -0
  50. metadata +317 -0
@@ -0,0 +1,5 @@
1
+ module ManageIQ
2
+ module ApplianceConsole
3
+ class MiqSignalError < RuntimeError; end
4
+ end
5
+ end
@@ -0,0 +1,153 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+
4
+ module ManageIQ
5
+ module ApplianceConsole
6
+ class ExternalAuthOptions
7
+ AUTH_PATH = "/authentication".freeze
8
+
9
+ EXT_AUTH_OPTIONS = {
10
+ "#{AUTH_PATH}/sso_enabled" => {:label => "Single Sign-On", :logic => true},
11
+ "#{AUTH_PATH}/saml_enabled" => {:label => "SAML", :logic => true},
12
+ "#{AUTH_PATH}/local_login_disabled" => {:label => "Local Login", :logic => false}
13
+ }.freeze
14
+
15
+ include ManageIQ::ApplianceConsole::Logging
16
+
17
+ def initialize
18
+ @updates = {}
19
+ @current_config = {}
20
+ end
21
+
22
+ def ask_questions
23
+ @current_config = load_current
24
+ apply = EXT_AUTH_OPTIONS.keys.count + 1
25
+ skip = apply + 1
26
+ selection = 0
27
+ while selection < apply
28
+ say("\nExternal Authentication Options:")
29
+ cnt = 1
30
+ EXT_AUTH_OPTIONS.keys.each do |key|
31
+ current_state = selected_value(key)
32
+ say("#{cnt}) #{selected_verb(key, !current_state)} #{EXT_AUTH_OPTIONS[key][:label]}")
33
+ cnt += 1
34
+ end
35
+ say("#{apply}) Apply updates")
36
+ say("#{skip}) Skip updates")
37
+ show_updates
38
+ selection = ask_for_integer("option number to apply", 1..skip)
39
+ if selection < apply
40
+ key = EXT_AUTH_OPTIONS.keys[selection - 1]
41
+ @updates[key] = !selected_value(key)
42
+ end
43
+ end
44
+ @updates = {} if selection == skip
45
+ true
46
+ end
47
+
48
+ def show_updates
49
+ updates_todo = ""
50
+ EXT_AUTH_OPTIONS.keys.each do |key|
51
+ next unless @updates.key?(key)
52
+ updates_todo << ", " if updates_todo.present?
53
+ updates_todo << " #{selected_verb(key, @updates[key])} #{EXT_AUTH_OPTIONS[key][:label]}"
54
+ end
55
+ updates_to_apply = updates_todo.present? ? "Updates to apply: #{updates_todo}" : ""
56
+ say("\n#{updates_to_apply}")
57
+ end
58
+
59
+ def selected_value(key)
60
+ return @updates[key] if @updates.key?(key)
61
+ return @current_config[key] if @current_config.key?(key)
62
+ false
63
+ end
64
+
65
+ def selected_verb(key, flag)
66
+ if EXT_AUTH_OPTIONS[key][:logic]
67
+ flag ? "Enable" : "Disable"
68
+ else
69
+ flag ? "Disable" : "Enable"
70
+ end
71
+ end
72
+
73
+ def any_updates?
74
+ @updates.present?
75
+ end
76
+
77
+ def update_configuration(update_hash = nil)
78
+ update_hash ||= @updates
79
+ if update_hash.present?
80
+ say("\nUpdating external authentication options on appliance ...")
81
+ params = update_hash.collect { |key, value| "#{key}=#{value}" }
82
+ result = ManageIQ::ApplianceConsole::Utilities.rake_run("evm:settings:set", params)
83
+ raise parse_errors(result).join(', ') if result.failure?
84
+ end
85
+ end
86
+
87
+ # extauth_opts option parser: syntax is key=value,key=value
88
+ # key is one of the EXT_AUTH_OPTIONS keys.
89
+ # value is one of 1, true, 0 or false.
90
+ #
91
+ def parse(options)
92
+ parsed_updates = {}
93
+ options.split(",").each do |keyval|
94
+ key, val = keyval.split('=')
95
+ key, val = normalize_key(key.to_s.strip), val.to_s.strip
96
+ unless EXT_AUTH_OPTIONS.key?(key)
97
+ message = "Unknown external authentication option #{key} specified"
98
+ message << ", supported options are #{EXT_AUTH_OPTIONS.keys.join(', ')}"
99
+ raise message
100
+ end
101
+
102
+ value = option_value(val)
103
+ raise("Invalid #{key} option value #{val} specified, must be true or false") if value.nil?
104
+ parsed_updates[key] = value
105
+ end
106
+ parsed_updates
107
+ end
108
+
109
+ def self.configured?
110
+ # DB Up and running
111
+ true
112
+ end
113
+
114
+ private
115
+
116
+ def load_current
117
+ say("\nFetching external authentication options from appliance ...")
118
+ result = ManageIQ::ApplianceConsole::Utilities.rake_run("evm:settings:get", EXT_AUTH_OPTIONS.keys)
119
+
120
+ if result.success?
121
+ return parse_response(result)
122
+ else
123
+ raise parse_errors(result).join(', ')
124
+ end
125
+ end
126
+
127
+ def parse_errors(result)
128
+ result.error.split("\n").collect { |line| line if line =~ /^error: /i }.compact
129
+ end
130
+
131
+ def normalize_key(key)
132
+ key.include?('/') ? key : "#{AUTH_PATH}/#{key}"
133
+ end
134
+
135
+ def parse_response(result)
136
+ result.output.split("\n").each_with_object({}) do |line, hash|
137
+ key, val = line.split("=")
138
+ hash[key] = parse_value(val)
139
+ end
140
+ end
141
+
142
+ def option_value(value)
143
+ return true if value == '1' || value =~ /true/i
144
+ return false if value == '0' || value =~ /false/i
145
+ nil
146
+ end
147
+
148
+ def parse_value(value)
149
+ value.present? ? option_value(value) : false
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,34 @@
1
+ module ManageIQ
2
+ module ApplianceConsole
3
+ class ExternalDatabaseConfiguration < DatabaseConfiguration
4
+ attr_accessor :action
5
+
6
+ def initialize(hash = {})
7
+ set_defaults
8
+ super
9
+ end
10
+
11
+ def set_defaults
12
+ self.username = "root"
13
+ self.port = DEFAULT_PORT
14
+ self.database = "vmdb_production"
15
+ end
16
+
17
+ def activate
18
+ ask_questions if host.nil?
19
+ super
20
+ end
21
+
22
+ def ask_questions
23
+ create_new_region_questions if action == :create
24
+ clear_screen
25
+ say("Database Configuration\n")
26
+ ask_for_database_credentials(false)
27
+ end
28
+
29
+ def post_activation
30
+ start_evm
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,157 @@
1
+ require "manageiq/appliance_console/external_httpd_authentication/external_httpd_configuration"
2
+
3
+ module ManageIQ
4
+ module ApplianceConsole
5
+ class ExternalHttpdAuthentication
6
+ include ExternalHttpdConfiguration
7
+
8
+ def initialize(host = nil, options = {})
9
+ @ipaserver, @domain, @password = nil
10
+ @host = host
11
+ @domain = options[:domain] || domain_from_host(host)
12
+ @realm = options[:realm]
13
+ @ipaserver = options[:ipaserver]
14
+ @principal = options[:principal] || "admin"
15
+ @password = options[:password]
16
+ @timestamp = Time.now.strftime(TIMESTAMP_FORMAT)
17
+
18
+ @ipaserver = fqdn(@ipaserver, @domain)
19
+ end
20
+
21
+ def ask_for_parameters
22
+ say("\nIPA Server Parameters:\n\n")
23
+ @ipaserver = ask_for_hostname("IPA Server Hostname", @ipaserver)
24
+ @domain = ask_for_domain("IPA Server Domain", @domain)
25
+ @realm = ask_for_string("IPA Server Realm", realm)
26
+ @principal = ask_for_string("IPA Server Principal", @principal)
27
+ @password = ask_for_password("IPA Server Principal Password", @password)
28
+
29
+ @ipaserver = fqdn(@ipaserver, @domain)
30
+ end
31
+
32
+ def show_parameters
33
+ say("\nExternal Authentication (httpd) Configuration:\n")
34
+ say("IPA Server Details:\n")
35
+ say(" Hostname: #{@ipaserver}\n")
36
+ say(" Domain: #{@domain}\n")
37
+ say(" Realm: #{realm}\n")
38
+ say(" Naming Context: #{domain_naming_context}\n")
39
+ say(" Principal: #{@principal}\n")
40
+ end
41
+
42
+ def show_current_configuration
43
+ return unless ipa_client_configured?
44
+ config = config_file_read(SSSD_CONFIG)
45
+ say("\nCurrent External Authentication (httpd) Configuration:\n")
46
+ say("IPA Server Details:\n")
47
+ say(" Hostname: #{fetch_ipa_configuration("ipa_server", config)}\n")
48
+ say(" Domain: #{fetch_ipa_configuration("ipa_domain", config)}\n")
49
+ end
50
+
51
+ def ask_questions
52
+ return false unless valid_environment?
53
+ ask_for_parameters
54
+ show_parameters
55
+ return false unless agree("\nProceed? (Y/N): ")
56
+ return false unless valid_parameters?(@ipaserver)
57
+ true
58
+ end
59
+
60
+ def activate
61
+ begin
62
+ configure_ipa
63
+ configure_pam
64
+ configure_sssd
65
+ configure_ipa_http_service
66
+ configure_httpd
67
+ configure_selinux
68
+ rescue AwesomeSpawn::CommandResultError => e
69
+ say e.result.output
70
+ say e.result.error
71
+ say ""
72
+ say("Failed to Configure External Authentication - #{e}")
73
+ return false
74
+ rescue => e
75
+ say("Failed to Configure External Authentication - #{e}")
76
+ return false
77
+ end
78
+ true
79
+ end
80
+
81
+ def post_activation
82
+ say("\nRestarting httpd, if running ...")
83
+ httpd_service = LinuxAdmin::Service.new("httpd")
84
+ httpd_service.restart if httpd_service.running?
85
+
86
+ say("Restarting sssd and configure it to start on reboots ...")
87
+ LinuxAdmin::Service.new("sssd").restart.enable
88
+ end
89
+
90
+ private
91
+
92
+ def domain_naming_context
93
+ @domain.split(".").collect { |s| "dc=#{s}" }.join(",")
94
+ end
95
+
96
+ def domain_from_host(host)
97
+ host.gsub(/^([^.]+\.)/, '') if host && host.include?('.')
98
+ end
99
+
100
+ def fqdn(host, domain)
101
+ (host && domain && !host.include?(".")) ? "#{host}.#{domain}" : host
102
+ end
103
+
104
+ def realm
105
+ (@realm || @domain).upcase
106
+ end
107
+
108
+ def configure_ipa
109
+ say("\nConfiguring IPA (may take a minute) ...")
110
+ ipa_client_unconfigure if ipa_client_configured?
111
+ ipa_client_configure(realm, @domain, @ipaserver, @principal, @password)
112
+ enable_kerberos_dns_lookups
113
+ end
114
+
115
+ def configure_pam
116
+ say("Configuring pam ...")
117
+ cp_template(PAM_CONFIG, template_directory)
118
+ end
119
+
120
+ def configure_sssd
121
+ say("Configuring sssd ...")
122
+ config = config_file_read(SSSD_CONFIG)
123
+ configure_sssd_domain(config, @domain)
124
+ configure_sssd_service(config)
125
+ configure_sssd_ifp(config)
126
+ config_file_write(config, SSSD_CONFIG, @timestamp)
127
+ end
128
+
129
+ def configure_ipa_http_service
130
+ say("Configuring IPA HTTP Service and Keytab ...")
131
+ AwesomeSpawn.run!("/usr/bin/kinit", :params => [@principal], :stdin_data => @password)
132
+ service = Principal.new(:hostname => @host, :realm => realm, :service => "HTTP", :ca_name => "ipa")
133
+ service.register
134
+ AwesomeSpawn.run!(IPA_GETKEYTAB, :params => {"-s" => @ipaserver, "-k" => HTTP_KEYTAB, "-p" => service.name})
135
+ FileUtils.chown(APACHE_USER, nil, HTTP_KEYTAB)
136
+ FileUtils.chmod(0600, HTTP_KEYTAB)
137
+ end
138
+
139
+ def configure_httpd
140
+ say("Configuring httpd ...")
141
+ configure_httpd_application
142
+ end
143
+
144
+ def configure_selinux
145
+ say("Configuring SELinux ...")
146
+ get_enforce = AwesomeSpawn.run!(GETENFORCE_COMMAND)
147
+ if get_enforce.output.downcase.include?("disabled")
148
+ say("SELinux is Disabled")
149
+ else
150
+ AwesomeSpawn.run!("#{SETSEBOOL_COMMAND} -P allow_httpd_mod_auth_pam on")
151
+ result = AwesomeSpawn.run("#{GETSEBOOL_COMMAND} httpd_dbus_sssd")
152
+ AwesomeSpawn.run!("#{SETSEBOOL_COMMAND} -P httpd_dbus_sssd on") if result.exit_status == 0
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,249 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+ require 'pathname'
3
+
4
+ module ManageIQ
5
+ module ApplianceConsole
6
+ class ExternalHttpdAuthentication
7
+ module ExternalHttpdConfiguration
8
+ #
9
+ # External Authentication Definitions
10
+ #
11
+ IPA_COMMAND = "/usr/bin/ipa".freeze
12
+ IPA_INSTALL_COMMAND = "/usr/sbin/ipa-client-install".freeze
13
+ IPA_GETKEYTAB = "/usr/sbin/ipa-getkeytab".freeze
14
+
15
+ KERBEROS_CONFIG_FILE = "/etc/krb5.conf".freeze
16
+
17
+ SSSD_CONFIG = "/etc/sssd/sssd.conf".freeze
18
+ PAM_CONFIG = "/etc/pam.d/httpd-auth".freeze
19
+ HTTP_KEYTAB = "/etc/http.keytab".freeze
20
+ HTTP_REMOTE_USER = "/etc/httpd/conf.d/manageiq-remote-user.conf".freeze
21
+ HTTP_EXTERNAL_AUTH = "/etc/httpd/conf.d/manageiq-external-auth.conf".freeze
22
+ HTTP_EXTERNAL_AUTH_TEMPLATE = "#{HTTP_EXTERNAL_AUTH}.erb".freeze
23
+
24
+ GETSEBOOL_COMMAND = "/usr/sbin/getsebool".freeze
25
+ SETSEBOOL_COMMAND = "/usr/sbin/setsebool".freeze
26
+ GETENFORCE_COMMAND = "/usr/sbin/getenforce".freeze
27
+
28
+ APACHE_USER = "apache".freeze
29
+
30
+ TIMESTAMP_FORMAT = "%Y%m%d_%H%M%S".freeze
31
+
32
+ LDAP_ATTRS = {
33
+ "mail" => "REMOTE_USER_EMAIL",
34
+ "givenname" => "REMOTE_USER_FIRSTNAME",
35
+ "sn" => "REMOTE_USER_LASTNAME",
36
+ "displayname" => "REMOTE_USER_FULLNAME",
37
+ "domainname" => "REMOTE_USER_DOMAIN"
38
+ }.freeze
39
+
40
+ def template_directory
41
+ Pathname.new(ENV.fetch("APPLIANCE_TEMPLATE_DIRECTORY"))
42
+ end
43
+
44
+ #
45
+ # IPA Configuration Methods
46
+ #
47
+ def ipa_client_configure(realm, domain, server, principal, password)
48
+ say("Configuring the IPA Client ...")
49
+ AwesomeSpawn.run!(IPA_INSTALL_COMMAND,
50
+ :params => [
51
+ "-N", :force_join, :fixed_primary, :unattended, {
52
+ :realm= => realm,
53
+ :domain= => domain,
54
+ :server= => server,
55
+ :principal= => principal,
56
+ :password= => password
57
+ }
58
+ ])
59
+ end
60
+
61
+ def deactivate
62
+ ipa_client_unconfigure
63
+ unconfigure_httpd
64
+ end
65
+
66
+ def ipa_client_unconfigure
67
+ say("Un-Configuring the IPA Client ...")
68
+ AwesomeSpawn.run(IPA_INSTALL_COMMAND, :params => [:uninstall, :unattended])
69
+ end
70
+
71
+ def unconfigure_httpd
72
+ say("Unconfiguring httpd ...")
73
+ unconfigure_httpd_application
74
+
75
+ say("Restarting httpd ...")
76
+ LinuxAdmin::Service.new("httpd").restart
77
+ end
78
+
79
+ def configure_httpd_application
80
+ cp_template(HTTP_EXTERNAL_AUTH_TEMPLATE, template_directory)
81
+ cp_template(HTTP_REMOTE_USER, template_directory)
82
+ end
83
+
84
+ def unconfigure_httpd_application
85
+ rm_file(HTTP_EXTERNAL_AUTH)
86
+ rm_file(HTTP_REMOTE_USER)
87
+ end
88
+
89
+ #
90
+ # Kerberos KRB5 File Methods
91
+ #
92
+ def enable_kerberos_dns_lookups
93
+ FileUtils.copy(KERBEROS_CONFIG_FILE, "#{KERBEROS_CONFIG_FILE}.miqbkp")
94
+ krb5config = File.read(KERBEROS_CONFIG_FILE)
95
+ krb5config[/(\s*)dns_lookup_kdc(\s*)=(\s*)(.*)/, 4] = 'true'
96
+ krb5config[/(\s*)dns_lookup_realm(\s*)=(\s*)(.*)/, 4] = 'true'
97
+ File.write(KERBEROS_CONFIG_FILE, krb5config)
98
+ end
99
+
100
+ #
101
+ # SSSD File Methods
102
+ #
103
+ def configure_sssd_domain(config, domain)
104
+ ldap_user_extra_attrs = LDAP_ATTRS.keys.join(", ")
105
+ if config.include?("ldap_user_extra_attrs = ")
106
+ pattern = "[domain/#{Regexp.escape(domain)}](\n.*)+ldap_user_extra_attrs = (.*)"
107
+ config[/#{pattern}/, 2] = ldap_user_extra_attrs
108
+ else
109
+ pattern = "[domain/#{Regexp.escape(domain)}].*(\n)"
110
+ config[/#{pattern}/, 1] = "\nldap_user_extra_attrs = #{ldap_user_extra_attrs}\n"
111
+ end
112
+
113
+ pattern = "[domain/#{Regexp.escape(domain)}].*(\n)"
114
+ config[/#{pattern}/, 1] = "\nentry_cache_timeout = 600\n"
115
+ end
116
+
117
+ def configure_sssd_service(config)
118
+ services = config.match(/\[sssd\](\n.*)+services = (.*)/)[2]
119
+ services = "#{services}, ifp" unless services.include?("ifp")
120
+ config[/\[sssd\](\n.*)+services = (.*)/, 2] = services
121
+ end
122
+
123
+ def configure_sssd_ifp(config)
124
+ user_attributes = LDAP_ATTRS.keys.collect { |k| "+#{k}" }.join(", ")
125
+ ifp_config = "
126
+ allowed_uids = #{APACHE_USER}, root
127
+ user_attributes = #{user_attributes}
128
+ "
129
+ if config.include?("[ifp]")
130
+ if config[/\[ifp\](\n.*)+user_attributes = (.*)/]
131
+ config[/\[ifp\](\n.*)+user_attributes = (.*)/, 2] = user_attributes
132
+ else
133
+ config[/\[ifp\](\n)/, 1] = ifp_config
134
+ end
135
+ else
136
+ config << "\n[ifp]#{ifp_config}\n"
137
+ end
138
+ end
139
+
140
+ #
141
+ # Validation Methods
142
+ #
143
+ def installation_valid?
144
+ installed_rpm_packages = LinuxAdmin::Rpm.list_installed.keys
145
+ rpm_packages = %w(ipa-client sssd-dbus mod_intercept_form_submit mod_authnz_pam mod_lookup_identity)
146
+
147
+ missing = rpm_packages.count do |package|
148
+ installed = installed_rpm_packages.include?(package)
149
+ say("#{package} RPM is not installed") unless installed
150
+ !installed
151
+ end
152
+
153
+ if missing > 0
154
+ say("\nAppliance Installation is not valid for enabling External Authentication\n")
155
+ return false
156
+ end
157
+
158
+ true
159
+ end
160
+
161
+ def valid_environment?
162
+ return false unless installation_valid?
163
+ if ipa_client_configured?
164
+ show_current_configuration
165
+ return false unless agree("\nIPA Client already configured on this Appliance, Un-Configure first? (Y/N): ")
166
+ deactivate
167
+ return false unless agree("\nProceed with External Authentication Configuration? (Y/N): ")
168
+ end
169
+ true
170
+ end
171
+
172
+ def valid_parameters?(ipaserver)
173
+ host_reachable?(ipaserver, "IPA Server")
174
+ end
175
+
176
+ #
177
+ # Config File I/O Methods
178
+ #
179
+ def config_file_write(config, path, timestamp)
180
+ FileUtils.copy(path, "#{path}.#{timestamp}") if File.exist?(path)
181
+ File.open(path, "w") { |f| f.write(config) }
182
+ end
183
+
184
+ #
185
+ # Network validation
186
+ #
187
+ def host_reachable?(host, what = "Server")
188
+ require 'net/ping'
189
+ say("Checking connectivity to #{host} ... ")
190
+ unless Net::Ping::External.new(host).ping
191
+ say("Failed.\nCould not connect to #{host},")
192
+ say("the #{what} must be reachable by name.")
193
+ return false
194
+ end
195
+ say("Succeeded.")
196
+ true
197
+ end
198
+
199
+ def cp_template(file, src_dir, dest_dir = "/")
200
+ src_path = path_join(src_dir, file)
201
+ dest_path = path_join(dest_dir, file.gsub(".erb", ""))
202
+ if src_path.to_s.include?(".erb")
203
+ File.write(dest_path, ERB.new(File.read(src_path), nil, '-').result(binding))
204
+ else
205
+ FileUtils.cp src_path, dest_path
206
+ end
207
+ end
208
+
209
+ def rm_file(file, dir = "/")
210
+ path = path_join(dir, file)
211
+ File.delete(path) if File.exist?(path)
212
+ end
213
+
214
+ def path_join(*args)
215
+ path = Pathname.new(args.shift)
216
+ args.each { |path_seg| path = path.join("./#{path_seg}") }
217
+ path
218
+ end
219
+ end
220
+
221
+ def self.config_status
222
+ fetch_ipa_configuration("ipa_server") || fetch_sssd_domain || "not configured"
223
+ end
224
+
225
+ def self.ipa_client_configured?
226
+ File.exist?(SSSD_CONFIG)
227
+ end
228
+
229
+ def self.config_file_read(path)
230
+ File.read(path)
231
+ end
232
+
233
+ def self.fetch_ipa_configuration(what, config = nil)
234
+ unless config
235
+ return nil unless ipa_client_configured?
236
+ config = config_file_read(SSSD_CONFIG)
237
+ end
238
+ pattern = "[domain/.*].*(\n.*)+#{Regexp.escape(what)} = (.*)"
239
+ config[/#{pattern}/, 2]
240
+ end
241
+
242
+ def self.fetch_sssd_domain
243
+ config_file_read(SSSD_CONFIG)[/\[domain\/(.*)\]/, 1] if File.exist?(SSSD_CONFIG)
244
+ end
245
+
246
+ delegate :ipa_client_configured?, :config_file_read, :fetch_ipa_configuration, :config_status, :to => self
247
+ end
248
+ end
249
+ end