/
auto.rb
281 lines (241 loc) · 8.43 KB
/
auto.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# ------------------------------------------------------------------------------
# Copyright (c) 2017 SUSE LLC
#
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of version 2 of the GNU General Public License as published by the
# Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, contact SUSE.
#
# To contact SUSE about this file by physical or electronic mail, you may find
# current contact information at www.suse.com.
# ------------------------------------------------------------------------------
require "yast"
require "y2firewall/firewalld"
require "y2firewall/autoyast"
require "installation/security_settings"
require "y2firewall/summary_presenter"
require "y2firewall/dialogs/main"
require "y2firewall/autoinst_profile/firewall_section"
require "installation/auto_client"
Yast.import "Mode"
Yast.import "AutoInstall"
module Y2Firewall
module Clients
# This is a client for autoinstallation. It takes its arguments,
# goes through the configuration and return the setting.
# Does not do any changes to the configuration.
class Auto < ::Installation::AutoClient
include Yast::Logger
class << self
# @return [Boolean] whether the AutoYaST configuration has been
# modified or not
attr_accessor :changed
# @return [Boolean] whether the AutoYaST configuration was imported
# successfully or not
attr_accessor :imported
# @return [Boolean] whether the firewalld service has to be enabled
# after writing the configuration
attr_accessor :enable
# @return [Boolean] whether the firewalld service has to be started
# after writing the configuration
attr_accessor :start
# @return [Hash]
attr_accessor :profile
# @return [Boolean] whether the AutoYaST configuration has been
# modified or not
attr_accessor :ay_config
end
# Constructor
def initialize
super()
textdomain "firewall"
end
# Configuration summary
#
# @return [String]
def summary
presenter = Y2Firewall::SummaryPresenter.new(firewalld)
return presenter.not_installed if !firewalld.installed?
return presenter.not_configured if !firewalld.read? && !firewalld.modified?
presenter.create
end
# Import the firewall configuration
#
# @param profile [Hash] firewall profile section to be imported
# @return [Boolean]
def import(profile, merge = !Yast::Mode.config)
self.class.profile = profile
return false if merge && !read(force: false)
# Obtains the default from the control file (settings) if not present.
enable if profile.fetch("enable_firewall", settings.enable_firewall)
start if profile.fetch("start_firewall", false)
autoyast.import(profile)
check_profile_for_errors
imported
end
# Export the current firewalld configuration
#
# @param target [Symbol] Control how much information should be exported
# (e.g., :default or :compact).
# @return [Hash] with the current firewalld configuration
def export(target: :default)
autoyast.export(target: target)
end
# Reset the current firewalld configuration.
#
# @return [Boolean]
def reset
firewalld.reset
self.class.ay_config = false
self.class.changed = false
end
def change
read_keeping_configuration
result = Dialogs::Main.new.run
case result
when :next, :finish, :ok, :accept
self.class.ay_config = true
end
result
end
# Write the imported configuration to firewalld. If for some reason the
# configuration was not imported from the profile, it tries to import
# it again.
def write
return false if !firewalld.installed?
import_if_needed
return false unless imported?
firewalld.write if firewalld.modified?
if ay_config?
firewalld.reset
firewalld.read(minimal: true)
import(self.class.profile, false)
else
activate_service
# Force a reset of the API instance (bsc#1166698)
firewalld.api = nil
end
end
# Read the currnet firewalld configuration
def read(force: true)
return false if !firewalld.installed?
return true if firewalld.read? && !force
modified
firewalld.read
end
# A map with the packages that needs to be installed or removed for
# configuring firewalld properly
#
# @return [Hash{String => Array<String>} ] of packages to be installed or removed
def packages
{ "install" => ["firewalld"], "remove" => [] }
end
def modified
self.class.changed = true
end
def modified?
!!self.class.changed
end
private
# Read the minimal configuration from firewalld, w/o dropping available configuration
#
# Useful to preserve the already imported, but not written yet, configuration (if any)
def read_keeping_configuration
return unless firewalld.installed?
return if firewalld.read?
self.class.profile = export
firewalld.reset
firewalld.read(minimal: true)
import(self.class.profile, false)
end
def import_if_needed
if ay_config?
self.class.profile = export
self.class.imported = false
end
import(self.class.profile) if self.class.profile && !imported?
end
def ay_config?
!!self.class.ay_config
end
# Semantic AutoYaST profile check
#
# Problems will be stored in AutoInstall.issues_list.
def check_profile_for_errors
# Checking if an interface has been defined for different zones
zones = export["zones"] || []
all_interfaces = zones.flat_map { |zone| zone["interfaces"] || [] }
double_entries = all_interfaces.select { |i| all_interfaces.count(i) > 1 }.uniq
return if double_entries.empty?
AutoInstall.issues_list.add(
::Installation::AutoinstIssues::InvalidValue,
Y2Firewall::AutoinstProfile::FirewallSection.new_from_hashes(
self.class.profile
),
"interfaces",
double_entries.join(","),
_("This interface has been defined for more than one zone.")
)
end
# Depending on the profile it activates or deactivates the firewalld
# service
def activate_service
enable? ? firewalld.enable! : firewalld.disable!
start? ? firewalld.start : firewalld.stop
end
# Return a firewall autoyast object
#
# @return [Y2Firewall::Autoyast]
def autoyast
@autoyast ||= Autoyast.new
end
# Return a firewalld singleton instance
#
# @return [Y2Firewall::Firewalld] singleton instance
def firewalld
Firewalld.instance
end
# @return [::Installation::SecuritySettings]
def settings
::Installation::SecuritySettings.instance
end
# Set that the firewall has to be enabled when writing
def enable
self.class.enable = true
end
# Whether the firewalld service has to be enable or disable when writing
#
# @return [Boolean] true if has to be enabled; false otherwise
def enable?
!!self.class.enable
end
# Set that the firewall has to be started when writing
def start
self.class.start = true
end
# Whether the firewalld service has to be started or stopped when writing
#
# @return [Boolean] true if has to be started; false otherwise
def start?
!!self.class.start
end
# Set that the firewalld configuration has been completely imported
def imported
self.class.imported = true
end
# Whether the firewalld configuration has been already imported or not
#
# @return [Boolean] true if has been imported; false otherwise
def imported?
!!self.class.imported
end
end
end
end