-
Notifications
You must be signed in to change notification settings - Fork 20
/
AutoinstFunctions.rb
258 lines (221 loc) · 8.7 KB
/
AutoinstFunctions.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
require "y2packager/product"
require "y2packager/product_reader"
require "y2packager/product_spec"
require "y2packager/medium_type"
module Yast
# Helper methods to be used on autoinstallation.
class AutoinstFunctionsClass < Module
include Yast::Logger
# special mapping for handling dropped or renamed products,
# a map with <old product name> => <new_product name> values
PRODUCT_MAPPING = {
# the SLE_HPC product was dropped and replaced by standard SLES in SP6
"SLE_HPC" => "SLES"
}.freeze
def main
textdomain "installation"
Yast.import "Stage"
Yast.import "Mode"
Yast.import "AutoinstConfig"
Yast.import "InstURL"
Yast.import "ProductControl"
Yast.import "Profile"
Yast.import "Pkg"
# Force to read the list of products from libzypp. See {#check_result} for
# further details.
@force_libzypp = false
end
# Determines if the second stage should be executed
#
# Checks Mode, AutoinstConfig and ProductControl to decide if it's
# needed.
#
# FIXME: It's almost equal to InstFunctions.second_stage_required?
# defined in yast2-installation, but exists to avoid a circular dependency
# between packages (yast2-installation -> autoyast2-installation).
#
# @return [Boolean] 'true' if it's needed; 'false' otherwise.
def second_stage_required?
return false unless Stage.initial
if (Mode.autoinst || Mode.autoupgrade) && !AutoinstConfig.second_stage
Builtins.y2milestone("Autoyast: second stage is disabled")
false
else
ProductControl.RunRequired("continue", Mode.mode)
end
end
# Checking the environment the installed system
# to run a second stage if it is needed.
#
# @return [String] empty String or error messsage about missing packages.
def check_second_stage_environment
error = ""
return error unless second_stage_required?
missing_packages = Profile.needed_second_stage_packages.reject do |p|
Pkg.IsSelected(p)
end
unless missing_packages.empty?
log.warn "Second stage cannot be run due missing packages: #{missing_packages}"
# TRANSLATORS: %s will be replaced by a package list
error = format(_("AutoYaST cannot run second stage due to missing packages \n%s.\n"),
missing_packages.join(", "))
unless registered?
if Profile.current["suse_register"] &&
Profile.current["suse_register"]["do_registration"] == true
error << _("The registration has failed. " \
"Please check your registration settings in the AutoYaST configuration file.")
log.warn "Registration has been called but has failed."
else
error << _("You have not registered your system. " \
"Missing packages can be added by configuring the registration " \
"in the AutoYaST configuration file.")
log.warn "Registration is not configured at all."
end
end
end
error
end
# Tries to find a base product if could be identified from the AY profile
#
# There are several ways how can base product be defined in the profile
# 1) explicitly
# 2) impllicitly according to software selection
# 3) if not set explicitly and just one product is available on media - use it
#
# @return [Y2Packager::ProductSpec] a base product or nil.
def selected_product
return @selected_product if @selected_product
profile = Profile.current
product = identify_product_by_selection(profile)
# user asked for a product which is not available -> exit, not found
return nil if product.nil? && base_product_name(profile)
@selected_product = if product
log.info("selected_product - found explicitly defined base product: #{product.inspect}")
product
elsif (product = identify_product_by_patterns(profile))
log.info("selected_product - base product identified by patterns: #{product.inspect}")
product
elsif (product = identify_product_by_packages(profile))
log.info("selected_product - base product identified by packages: #{product.inspect}")
product
else
# last instance
base_products = available_base_products
base_products.first if base_products.size == 1
end
@selected_product
end
#
# Evaluate all available base products and returns a list of product.
# CAUTION: The type of the return values depend of the kind of where
# the product information has been read (libzypp, or product specs).
# So the type could be Product or ProductSpec derived class.
#
# The behaviour of this method can be affected by the `force_libzypp` attribute.
# Check {#reset_product} for further details.
#
# @return [Array<Y2Packager::Product|Y2Packager::ProductSpec>] List of base products
def available_base_products
return @base_products if @base_products
@base_products = Y2Packager::ProductReader.new.available_base_products(
force_repos: @force_libzypp
)
return @base_products if @force_libzypp
libzypp_names = @base_products.map(&:name)
Y2Packager::ProductSpec.base_products.each do |product|
@base_products << product unless libzypp_names.include?(product.name)
end
@base_products
end
# force selected product to be read from libzypp and not from product location
def reset_product
@selected_product = nil
@base_products = nil
@force_libzypp = true
end
private
# Determine whether the system is registered
#
# @return [Boolean]
def registered?
require "registration/registration"
Registration::Registration.is_registered?
rescue LoadError
false
end
# Tries to identify a base product according to the condition in block
#
# @return [Y2Packager::Product] a product if exactly one product matches
# the criteria, nil otherwise
def identify_product
log.info "Found base products : #{available_base_products.inspect}"
products = available_base_products.select do |product|
yield(product.name)
end
return products.first if products.size == 1
nil
end
# Try to find base product according to patterns in profile
#
# searching for patterns like "sles-base-32bit"
#
# @param [Hash] profile - a hash representation of AY profile
# @return [Y2Packager::Product] a product if exactly one product matches
# the criteria, nil otherwise
def identify_product_by_patterns(profile)
software = profile.fetch_as_hash("software")
identify_product do |name|
software.fetch_as_array("patterns").any? { |p| p =~ /#{name.downcase}-.*/ }
end
end
# Try to find base product according to packages selection in profile
#
# searching for packages like "sles-release"
#
# @param [Hash] profile - a hash representation of AY profile
# @return [Y2Packager::Product] a product if exactly one product matches
# the criteria, nil otherwise
def identify_product_by_packages(profile)
software = profile.fetch_as_hash("software")
identify_product do |name|
software.fetch_as_array("packages").any? { |p| p =~ /#{name.downcase}-release/ }
end
end
# Try to identify base product using user's selection in profile
#
# @param [Hash] profile - a hash representation of AY profile
# @return [Y2Packager::Product] a product if exactly one product matches
# the criteria, nil otherwise
def identify_product_by_selection(profile)
identify_product do |name|
name == base_product_name(profile)
end
end
# Reads base product name from the profile
#
# FIXME: Currently it returns first found product name. It should be no
# problem since this section was unused in AY installation so far.
# However, it might be needed to add a special handling for multiple
# products in the future. At least we can filter out products which are
# not base products.
#
# @param profile [Hash] AutoYaST profile
# @return [String] product name
def base_product_name(profile)
software = profile.fetch_as_hash("software", nil)
if software.nil?
log.info("Error: given profile has not a valid software section")
return nil
end
product = software.fetch_as_array("products").first
new_product = PRODUCT_MAPPING[product]
if new_product
log.info "Replacing requested product #{product.inspect} with #{new_product.inspect}"
return new_product
end
product
end
end
AutoinstFunctions = AutoinstFunctionsClass.new
AutoinstFunctions.main
end