d-installer 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +75 -0
- data/bin/d-installer +74 -0
- data/etc/d-installer.yaml +284 -0
- data/lib/dinstaller/can_ask_question.rb +48 -0
- data/lib/dinstaller/cmdline_args.rb +80 -0
- data/lib/dinstaller/cockpit_manager.rb +176 -0
- data/lib/dinstaller/config.rb +128 -0
- data/lib/dinstaller/config_reader.rb +164 -0
- data/lib/dinstaller/dbus/base_object.rb +58 -0
- data/lib/dinstaller/dbus/clients/base.rb +71 -0
- data/lib/dinstaller/dbus/clients/language.rb +86 -0
- data/lib/dinstaller/dbus/clients/manager.rb +76 -0
- data/lib/dinstaller/dbus/clients/software.rb +185 -0
- data/lib/dinstaller/dbus/clients/users.rb +112 -0
- data/lib/dinstaller/dbus/clients/with_progress.rb +56 -0
- data/lib/dinstaller/dbus/clients/with_service_status.rb +75 -0
- data/lib/dinstaller/dbus/clients.rb +34 -0
- data/lib/dinstaller/dbus/interfaces/progress.rb +113 -0
- data/lib/dinstaller/dbus/interfaces/service_status.rb +89 -0
- data/lib/dinstaller/dbus/language.rb +93 -0
- data/lib/dinstaller/dbus/language_service.rb +92 -0
- data/lib/dinstaller/dbus/manager.rb +147 -0
- data/lib/dinstaller/dbus/manager_service.rb +132 -0
- data/lib/dinstaller/dbus/question.rb +176 -0
- data/lib/dinstaller/dbus/questions.rb +124 -0
- data/lib/dinstaller/dbus/service_runner.rb +97 -0
- data/lib/dinstaller/dbus/service_status.rb +87 -0
- data/lib/dinstaller/dbus/software/manager.rb +131 -0
- data/lib/dinstaller/dbus/software/proposal.rb +82 -0
- data/lib/dinstaller/dbus/software.rb +31 -0
- data/lib/dinstaller/dbus/software_service.rb +86 -0
- data/lib/dinstaller/dbus/storage/proposal.rb +170 -0
- data/lib/dinstaller/dbus/storage.rb +30 -0
- data/lib/dinstaller/dbus/users.rb +132 -0
- data/lib/dinstaller/dbus/users_service.rb +92 -0
- data/lib/dinstaller/dbus/with_service_status.rb +48 -0
- data/lib/dinstaller/dbus/y2dir/manager/modules/Package.rb +51 -0
- data/lib/dinstaller/dbus/y2dir/manager/modules/PackagesProposal.rb +62 -0
- data/lib/dinstaller/dbus/y2dir/modules/Autologin.rb +214 -0
- data/lib/dinstaller/dbus/y2dir/software/modules/SpaceCalculation.rb +44 -0
- data/lib/dinstaller/dbus.rb +11 -0
- data/lib/dinstaller/errors.rb +28 -0
- data/lib/dinstaller/installation_phase.rb +106 -0
- data/lib/dinstaller/language.rb +73 -0
- data/lib/dinstaller/luks_activation_question.rb +92 -0
- data/lib/dinstaller/manager.rb +261 -0
- data/lib/dinstaller/network.rb +53 -0
- data/lib/dinstaller/package_callbacks.rb +69 -0
- data/lib/dinstaller/progress.rb +149 -0
- data/lib/dinstaller/question.rb +103 -0
- data/lib/dinstaller/questions_manager.rb +145 -0
- data/lib/dinstaller/security.rb +96 -0
- data/lib/dinstaller/service_status_recorder.rb +58 -0
- data/lib/dinstaller/software.rb +232 -0
- data/lib/dinstaller/storage/actions.rb +90 -0
- data/lib/dinstaller/storage/callbacks/activate.rb +93 -0
- data/lib/dinstaller/storage/callbacks/activate_luks.rb +93 -0
- data/lib/dinstaller/storage/callbacks/activate_multipath.rb +77 -0
- data/lib/dinstaller/storage/callbacks.rb +30 -0
- data/lib/dinstaller/storage/manager.rb +104 -0
- data/lib/dinstaller/storage/proposal.rb +197 -0
- data/lib/dinstaller/storage.rb +30 -0
- data/lib/dinstaller/users.rb +156 -0
- data/lib/dinstaller/with_progress.rb +63 -0
- data/lib/dinstaller.rb +5 -0
- data/share/dbus.conf +38 -0
- data/share/dbus.service +5 -0
- data/share/systemd.service +14 -0
- metadata +295 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
module DInstaller
|
23
|
+
# Manager for questions
|
24
|
+
#
|
25
|
+
# Allows to configure callbacks with the actions to perform when adding, deleting or waiting for
|
26
|
+
# questions.
|
27
|
+
class QuestionsManager
|
28
|
+
# @return [Array<Question>]
|
29
|
+
attr_reader :questions
|
30
|
+
|
31
|
+
# Constructor
|
32
|
+
#
|
33
|
+
# @params logger [Logger]
|
34
|
+
def initialize(logger)
|
35
|
+
@logger = logger
|
36
|
+
@questions = []
|
37
|
+
@on_add_callbacks = []
|
38
|
+
@on_delete_callbacks = []
|
39
|
+
@on_wait_callbacks = []
|
40
|
+
end
|
41
|
+
|
42
|
+
# Adds a question
|
43
|
+
#
|
44
|
+
# Callbacks are called after adding the question, see {#on_add}.
|
45
|
+
#
|
46
|
+
# @yieldparam question [Question] added question
|
47
|
+
#
|
48
|
+
# @param question [Question]
|
49
|
+
# @return [Boolean] whether the question was added
|
50
|
+
def add(question)
|
51
|
+
return false if include?(question)
|
52
|
+
|
53
|
+
questions << question
|
54
|
+
on_add_callbacks.each { |c| c.call(question) }
|
55
|
+
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
# Deletes the given question
|
60
|
+
#
|
61
|
+
# Callbacks are called after deleting the question, see {#on_delete}.
|
62
|
+
#
|
63
|
+
# @yieldparam question [Question] deleted question
|
64
|
+
#
|
65
|
+
# @param question [Question]
|
66
|
+
# @return [Boolean] whether the question was deleted
|
67
|
+
def delete(question)
|
68
|
+
return false unless include?(question)
|
69
|
+
|
70
|
+
questions.delete(question)
|
71
|
+
on_delete_callbacks.each { |c| c.call(question) }
|
72
|
+
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
# Waits until all questions are answered
|
77
|
+
#
|
78
|
+
# Callbacks are periodically called while waiting, see {#on_wait}.
|
79
|
+
def wait
|
80
|
+
logger.info "Waiting for questions to be answered"
|
81
|
+
|
82
|
+
loop do
|
83
|
+
on_wait_callbacks.each(&:call)
|
84
|
+
sleep(0.1)
|
85
|
+
break if questions_answered?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Registers a callback to be called when a new question is added
|
90
|
+
#
|
91
|
+
# @param block [Proc]
|
92
|
+
def on_add(&block)
|
93
|
+
on_add_callbacks << block
|
94
|
+
end
|
95
|
+
|
96
|
+
# Registers a callback to be called when a question is deleted
|
97
|
+
#
|
98
|
+
# @param block [Proc]
|
99
|
+
def on_delete(&block)
|
100
|
+
on_delete_callbacks << block
|
101
|
+
end
|
102
|
+
|
103
|
+
# Registers a callback to be called while waiting for questions be answered
|
104
|
+
#
|
105
|
+
# @param block [Proc]
|
106
|
+
def on_wait(&block)
|
107
|
+
on_wait_callbacks << block
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# @return [Logger]
|
113
|
+
attr_reader :logger
|
114
|
+
|
115
|
+
# Callbacks to be called when the a new question is added
|
116
|
+
#
|
117
|
+
# @return [Array<Proc>]
|
118
|
+
attr_reader :on_add_callbacks
|
119
|
+
|
120
|
+
# Callbacks to be called when the a question is deleted
|
121
|
+
#
|
122
|
+
# @return [Array<Proc>]
|
123
|
+
attr_reader :on_delete_callbacks
|
124
|
+
|
125
|
+
# Callbacks to be called when waiting for answers
|
126
|
+
#
|
127
|
+
# @return [Array<Proc>]
|
128
|
+
attr_reader :on_wait_callbacks
|
129
|
+
|
130
|
+
# Whether a question with the same id as the given question is already in the list of questions
|
131
|
+
#
|
132
|
+
# @param question [Question]
|
133
|
+
# @return [Boolean]
|
134
|
+
def include?(question)
|
135
|
+
questions.any? { |q| q.id == question.id }
|
136
|
+
end
|
137
|
+
|
138
|
+
# Whether all questions are already answered
|
139
|
+
#
|
140
|
+
# @return [Boolean]
|
141
|
+
def questions_answered?
|
142
|
+
questions.all?(&:answered?)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "yast"
|
23
|
+
require "y2security/lsm"
|
24
|
+
require "yast2/execute"
|
25
|
+
|
26
|
+
require "dinstaller/config"
|
27
|
+
|
28
|
+
# FIXME: monkey patching of security config to not read control.xml and
|
29
|
+
# instead use DIinstaller::Config
|
30
|
+
# TODO: add ability to set product features in LSM::Base
|
31
|
+
module Y2Security
|
32
|
+
module LSM
|
33
|
+
# modified LSM Base class to use dinstaller config
|
34
|
+
class Base
|
35
|
+
def product_feature_settings
|
36
|
+
return @product_feature_settings unless @product_feature_settings.nil?
|
37
|
+
|
38
|
+
value = ::DInstaller::Config.current.data["security"]["available_lsms"][id.to_s]
|
39
|
+
res = if value
|
40
|
+
{
|
41
|
+
selectable: true,
|
42
|
+
configurable: true,
|
43
|
+
patterns: (value["patterns"] || []).join(" "),
|
44
|
+
mode: value["policy"]
|
45
|
+
}
|
46
|
+
else
|
47
|
+
{
|
48
|
+
selectable: false,
|
49
|
+
configurable: false,
|
50
|
+
patterns: "",
|
51
|
+
mode: nil
|
52
|
+
}
|
53
|
+
end
|
54
|
+
@product_feature_settings = res
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module DInstaller
|
61
|
+
# Backend class between dbus service and yast code
|
62
|
+
class Security
|
63
|
+
# @return [Logger]
|
64
|
+
attr_reader :logger
|
65
|
+
|
66
|
+
def initialize(logger, config)
|
67
|
+
@config = config
|
68
|
+
@logger = logger
|
69
|
+
end
|
70
|
+
|
71
|
+
def write
|
72
|
+
lsm_config.save
|
73
|
+
end
|
74
|
+
|
75
|
+
def probe
|
76
|
+
selected_lsm = config.data["security"]["lsm"]
|
77
|
+
lsm_config.select(selected_lsm)
|
78
|
+
|
79
|
+
patterns = if selected_lsm.nil?
|
80
|
+
[]
|
81
|
+
else
|
82
|
+
lsm_data = config.data["security"]["available_lsms"][selected_lsm]
|
83
|
+
lsm_data["patterns"]
|
84
|
+
end
|
85
|
+
Yast::PackagesProposal.SetResolvables("LSM", :pattern, patterns)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
attr_reader :config
|
91
|
+
|
92
|
+
def lsm_config
|
93
|
+
Y2Security::LSM::Config.instance
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "dinstaller/dbus/service_status"
|
23
|
+
|
24
|
+
module DInstaller
|
25
|
+
# Allows to record the status of services and to register callbacks to be called when a service
|
26
|
+
# status changes its value
|
27
|
+
class ServiceStatusRecorder
|
28
|
+
def initialize
|
29
|
+
@statuses = {}
|
30
|
+
@on_service_status_change_callbacks = []
|
31
|
+
end
|
32
|
+
|
33
|
+
# Saves the status of the given service and runs the callbacks if the status has changed
|
34
|
+
#
|
35
|
+
# @param service_name [String]
|
36
|
+
# @param status [String] see {ServiceStatus}
|
37
|
+
def save(service_name, status)
|
38
|
+
return if @statuses[service_name] == status
|
39
|
+
|
40
|
+
@statuses[service_name] = status
|
41
|
+
@on_service_status_change_callbacks.each(&:call)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Name of services with busy status
|
45
|
+
#
|
46
|
+
# @return [Array<String>]
|
47
|
+
def busy_services
|
48
|
+
@statuses.select { |_service, status| status == DBus::ServiceStatus::BUSY }.keys
|
49
|
+
end
|
50
|
+
|
51
|
+
# Registers callbacks to be called when saving a new status
|
52
|
+
#
|
53
|
+
# @param block [Proc]
|
54
|
+
def on_service_status_change(&block)
|
55
|
+
@on_service_status_change_callbacks << block
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2021] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "yast"
|
23
|
+
require "fileutils"
|
24
|
+
require "dinstaller/package_callbacks"
|
25
|
+
require "dinstaller/config"
|
26
|
+
require "dinstaller/with_progress"
|
27
|
+
require "y2packager/product"
|
28
|
+
|
29
|
+
Yast.import "PackageInstallation"
|
30
|
+
Yast.import "Pkg"
|
31
|
+
Yast.import "Stage"
|
32
|
+
|
33
|
+
# YaST specific code lives under this namespace
|
34
|
+
module DInstaller
|
35
|
+
# This class is responsible for software handling
|
36
|
+
class Software
|
37
|
+
include WithProgress
|
38
|
+
|
39
|
+
GPG_KEYS_GLOB = "/usr/lib/rpm/gnupg/keys/gpg-*"
|
40
|
+
private_constant :GPG_KEYS_GLOB
|
41
|
+
|
42
|
+
attr_reader :product
|
43
|
+
|
44
|
+
DEFAULT_LANGUAGES = ["en_US"].freeze
|
45
|
+
private_constant :DEFAULT_LANGUAGES
|
46
|
+
|
47
|
+
attr_accessor :languages
|
48
|
+
|
49
|
+
# FIXME: what about defining a Product class?
|
50
|
+
# @return [Array<Array<String,Hash>>] An array containing the product ID and
|
51
|
+
# additional information in a hash
|
52
|
+
attr_reader :products
|
53
|
+
|
54
|
+
def initialize(config, logger)
|
55
|
+
@config = config
|
56
|
+
@logger = logger
|
57
|
+
@languages = DEFAULT_LANGUAGES
|
58
|
+
@products = @config.data["products"]
|
59
|
+
if @config.multi_product?
|
60
|
+
@product = nil
|
61
|
+
else
|
62
|
+
@product = @products.keys.first # use the available product as default
|
63
|
+
@config.pick_product(@product)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def select_product(name)
|
68
|
+
return if name == @product
|
69
|
+
raise ArgumentError unless @products[name]
|
70
|
+
|
71
|
+
@config.pick_product(name)
|
72
|
+
@product = name
|
73
|
+
end
|
74
|
+
|
75
|
+
def probe
|
76
|
+
logger.info "Probing software"
|
77
|
+
|
78
|
+
store_original_repos
|
79
|
+
Yast::Pkg.SetSolverFlags("ignoreAlreadyRecommended" => false, "onlyRequires" => true)
|
80
|
+
|
81
|
+
# as we use liveDVD with normal like ENV, lets temporary switch to normal to use its repos
|
82
|
+
Yast::Stage.Set("normal")
|
83
|
+
|
84
|
+
start_progress(3)
|
85
|
+
progress.step("Initialize target repositories") { initialize_target_repos }
|
86
|
+
progress.step("Initialize sources") { add_base_repo }
|
87
|
+
progress.step("Making the initial proposal") do
|
88
|
+
proposal = Yast::Packages.Proposal(force_reset = true, reinit = false, _simple = true)
|
89
|
+
logger.info "proposal #{proposal["raw_proposal"]}"
|
90
|
+
end
|
91
|
+
|
92
|
+
Yast::Stage.Set("initial")
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize_target_repos
|
96
|
+
Yast::Pkg.TargetInitialize("/")
|
97
|
+
import_gpg_keys
|
98
|
+
end
|
99
|
+
|
100
|
+
def propose
|
101
|
+
Yast::Pkg.TargetFinish # ensure that previous target is closed
|
102
|
+
Yast::Pkg.TargetInitialize(Yast::Installation.destdir)
|
103
|
+
Yast::Pkg.TargetLoad
|
104
|
+
Yast::Pkg.SetAdditionalLocales(languages)
|
105
|
+
select_base_product(@config.data["software"]["base_product"])
|
106
|
+
|
107
|
+
add_resolvables
|
108
|
+
proposal = Yast::Packages.Proposal(force_reset = false, reinit = false, _simple = true)
|
109
|
+
logger.info "proposal #{proposal["raw_proposal"]}"
|
110
|
+
|
111
|
+
solve_dependencies
|
112
|
+
|
113
|
+
# do not return proposal hash, so intentional nil here
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def install
|
118
|
+
start_progress(count_packages)
|
119
|
+
PackageCallbacks.setup(count_packages, progress)
|
120
|
+
|
121
|
+
# TODO: error handling
|
122
|
+
commit_result = Yast::PackageInstallation.Commit({})
|
123
|
+
|
124
|
+
if commit_result.nil? || commit_result.empty?
|
125
|
+
logger.error("Commit failed")
|
126
|
+
raise Yast::Pkg.LastError
|
127
|
+
end
|
128
|
+
|
129
|
+
logger.info "Commit result #{commit_result}"
|
130
|
+
end
|
131
|
+
|
132
|
+
# Writes the repositories information to the installed system
|
133
|
+
def finish
|
134
|
+
start_progress(2)
|
135
|
+
progress.step("Writing repositories to the target system") do
|
136
|
+
Yast::Pkg.SourceSaveAll
|
137
|
+
Yast::Pkg.TargetFinish
|
138
|
+
Yast::Pkg.SourceCacheCopyTo(Yast::Installation.destdir)
|
139
|
+
end
|
140
|
+
progress.step("Restoring original repositories") { restore_original_repos }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Determine whether the given tag is provided by the selected packages
|
144
|
+
#
|
145
|
+
# @param tag [String] Tag to search for (package names, requires/provides, or file
|
146
|
+
# names)
|
147
|
+
# @return [Boolean] true if it is provided; false otherwise
|
148
|
+
def provision_selected?(tag)
|
149
|
+
Yast::Pkg.IsSelected(tag) || Yast::Pkg.IsProvided(tag)
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
# adds resolvables from yaml config for given product
|
155
|
+
def add_resolvables
|
156
|
+
mandatory_patterns = @config.data["software"]["mandatory_patterns"] || []
|
157
|
+
Yast::PackagesProposal.SetResolvables("d-installer", :pattern, mandatory_patterns)
|
158
|
+
|
159
|
+
optional_patterns = @config.data["software"]["optional_patterns"] || []
|
160
|
+
Yast::PackagesProposal.SetResolvables("d-installer", :pattern, optional_patterns,
|
161
|
+
optional: true)
|
162
|
+
end
|
163
|
+
|
164
|
+
# call solver to satisfy dependency or log error
|
165
|
+
def solve_dependencies
|
166
|
+
res = Yast::Pkg.PkgSolve(unused = true)
|
167
|
+
logger.info "solver run #{res.inspect}"
|
168
|
+
|
169
|
+
return if res
|
170
|
+
|
171
|
+
logger.error "Solver failed: #{Yast::Pkg.LastError}"
|
172
|
+
logger.error "Details: #{Yast::Pkg.LastErrorDetails}"
|
173
|
+
logger.error "Solving issues: #{Yast::Pkg.PkgSolveErrors}"
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [Logger]
|
177
|
+
attr_reader :logger
|
178
|
+
|
179
|
+
def count_packages
|
180
|
+
Yast::Pkg.PkgMediaCount.reduce(0) { |sum, res| sum + res.reduce(0, :+) }
|
181
|
+
end
|
182
|
+
|
183
|
+
def import_gpg_keys
|
184
|
+
gpg_keys = Dir.glob(GPG_KEYS_GLOB).map(&:to_s)
|
185
|
+
logger.info "Importing GPG keys: #{gpg_keys}"
|
186
|
+
gpg_keys.each do |path|
|
187
|
+
Yast::Pkg.ImportGPGKey(path, true)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def add_base_repo
|
192
|
+
@config.data["software"]["installation_repositories"].each do |repo|
|
193
|
+
Yast::Pkg.SourceCreate(repo, "/") # TODO: having that dir also in config?
|
194
|
+
end
|
195
|
+
|
196
|
+
Yast::Pkg.SourceSaveAll
|
197
|
+
end
|
198
|
+
|
199
|
+
def select_base_product(name)
|
200
|
+
base_product = Y2Packager::Product.available_base_products.find do |product|
|
201
|
+
product.name == name
|
202
|
+
end
|
203
|
+
logger.info "Base product to select: #{base_product&.name}"
|
204
|
+
base_product&.select
|
205
|
+
end
|
206
|
+
|
207
|
+
REPOS_BACKUP = "/etc/zypp/repos.d.dinstaller.backup"
|
208
|
+
private_constant :REPOS_BACKUP
|
209
|
+
|
210
|
+
REPOS_DIR = "/etc/zypp/repos.d"
|
211
|
+
private_constant :REPOS_DIR
|
212
|
+
|
213
|
+
# ensure that repos backup is there and repos.d is empty
|
214
|
+
def store_original_repos
|
215
|
+
# Backup was already created, so just remove all repos
|
216
|
+
if File.directory?(REPOS_BACKUP)
|
217
|
+
logger.info "removing #{REPOS_DIR}"
|
218
|
+
FileUtils.rm_rf(REPOS_DIR)
|
219
|
+
else # move repos to backup
|
220
|
+
logger.info "moving #{REPOS_DIR} to #{REPOS_BACKUP}"
|
221
|
+
FileUtils.mv(REPOS_DIR, REPOS_BACKUP)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def restore_original_repos
|
226
|
+
logger.info "removing #{REPOS_DIR}"
|
227
|
+
FileUtils.rm_rf(REPOS_DIR)
|
228
|
+
logger.info "moving #{REPOS_BACKUP} to #{REPOS_DIR}"
|
229
|
+
FileUtils.mv(REPOS_BACKUP, REPOS_DIR)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) [2022] SUSE LLC
|
4
|
+
#
|
5
|
+
# All Rights Reserved.
|
6
|
+
#
|
7
|
+
# This program is free software; you can redistribute it and/or modify it
|
8
|
+
# under the terms of version 2 of the GNU General Public License as published
|
9
|
+
# by the Free Software Foundation.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
13
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
14
|
+
# more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License along
|
17
|
+
# with this program; if not, contact SUSE LLC.
|
18
|
+
#
|
19
|
+
# To contact SUSE LLC about this file by physical or electronic mail, you may
|
20
|
+
# find current contact information at www.suse.com.
|
21
|
+
|
22
|
+
require "y2storage/storage_manager"
|
23
|
+
|
24
|
+
module DInstaller
|
25
|
+
module Storage
|
26
|
+
# Backend class to get the list of actions over the storage devices
|
27
|
+
class Actions
|
28
|
+
# @param logger [Logger]
|
29
|
+
def initialize(logger)
|
30
|
+
@logger = logger
|
31
|
+
end
|
32
|
+
|
33
|
+
# All actions properly sorted
|
34
|
+
#
|
35
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
36
|
+
def all
|
37
|
+
main_actions + subvolume_actions
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @param [Logger]
|
43
|
+
attr_reader :logger
|
44
|
+
|
45
|
+
# Sorted main actions (everything except subvolume actions)
|
46
|
+
#
|
47
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
48
|
+
def main_actions
|
49
|
+
actions = self.actions.reject { |a| subvol_action?(a) }
|
50
|
+
sort_actions(actions)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sorted subvolume actions
|
54
|
+
#
|
55
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
56
|
+
def subvolume_actions
|
57
|
+
actions = self.actions.select { |a| subvol_action?(a) }
|
58
|
+
sort_actions(actions)
|
59
|
+
end
|
60
|
+
|
61
|
+
# All actions, without sorting
|
62
|
+
#
|
63
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
64
|
+
def actions
|
65
|
+
actiongraph = Y2Storage::StorageManager.instance.staging.actiongraph
|
66
|
+
|
67
|
+
return [] unless actiongraph
|
68
|
+
|
69
|
+
actiongraph.compound_actions
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sorts actions, placing destructive actions at the end
|
73
|
+
#
|
74
|
+
# @param actions [Array<Y2Storage::CompoundAction>]
|
75
|
+
# @return [Array<Y2Storage::CompoundAction>]
|
76
|
+
def sort_actions(actions)
|
77
|
+
delete, other = actions.partition(&:delete?)
|
78
|
+
delete.concat(other)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Whether the action acts over a Btrfs subvolume
|
82
|
+
#
|
83
|
+
# @param action [Y2Storage::CompoundAction]
|
84
|
+
# @return [Boolean]
|
85
|
+
def subvol_action?(action)
|
86
|
+
action.device_is?(:btrfs_subvolume)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|