diff --git a/doc/testing_wsl.md b/doc/testing_wsl.md new file mode 100644 index 0000000..4a582fc --- /dev/null +++ b/doc/testing_wsl.md @@ -0,0 +1,19 @@ +## Testing WSL Changes + +This document serve as reminder how is the optimal way to test changes done for WSL firstboot as working with +windows server can be linux unfriendly and we would like to test without any mocking to get the best results. + +### Creating Testing APPX + +The easiest way is to use OBS. Find the target release for WSL image like `SUSE:SLE-15-SP6:Update:WSL` +and branch there `kiwi-images-wsl` that is responsible for creation of appx. In your branch create package +yast2-firstboot ( as it is usually inherited from target and does not live in WSL subproject ) and copy there +modified sources with rake tarball. It is also mandatory to link or branch package `wsl-appx` as it ensures +that certificate used for appx matches with the one used in kiwi. +Another important think is to ensure that certificate for home repo is valid and not outdated. To check it use +`osc signkey --sslcert home:...` and if it is invalid use `osc signkey --sslcert --create home:...`. + +### Installing Modified APPX + +Just follow instructions at https://en.opensuse.org/WSL/Manual_Installation +Appx installer reports quite useless error when there is any issue, so use help at https://en.opensuse.org/WSL/Debugging_Hints diff --git a/package/yast2-firstboot.changes b/package/yast2-firstboot.changes index 3b4ab23..032ce21 100644 --- a/package/yast2-firstboot.changes +++ b/package/yast2-firstboot.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Dec 14 20:38:43 UTC 2023 - Josef Reidinger + +- Allow selecting WSL systemd pattern (jsc#PED-5644, jsc#PED-5099) +- 4.6.3 + ------------------------------------------------------------------- Fri Sep 01 19:57:03 UTC 2023 - Josef Reidinger diff --git a/package/yast2-firstboot.spec b/package/yast2-firstboot.spec index 7e8997e..2fb06b5 100644 --- a/package/yast2-firstboot.spec +++ b/package/yast2-firstboot.spec @@ -17,7 +17,7 @@ Name: yast2-firstboot -Version: 4.6.2 +Version: 4.6.3 Release: 0 Summary: YaST2 - Initial System Configuration License: GPL-2.0-only diff --git a/src/lib/y2firstboot/clients/wsl_product_selection.rb b/src/lib/y2firstboot/clients/wsl_product_selection.rb index 6daab24..271532d 100644 --- a/src/lib/y2firstboot/clients/wsl_product_selection.rb +++ b/src/lib/y2firstboot/clients/wsl_product_selection.rb @@ -38,12 +38,17 @@ def run return :auto if products.none? dialog = Dialogs::WSLProductSelection.new(products, - default_product: product, - wsl_gui_pattern: wsl_gui_pattern?) + default_product: product, + wsl_gui_pattern: wsl_gui_pattern?, + wsl_systemd_pattern: wsl_systemd_pattern?) result = dialog.run - save(product: dialog.product, wsl_gui_pattern: dialog.wsl_gui_pattern) if result == :next + if result == :next + save(product: dialog.product, + wsl_gui_pattern: dialog.wsl_gui_pattern, + wsl_systemd_pattern: dialog.wsl_systemd_pattern) + end result end @@ -52,14 +57,17 @@ def run WSL_GUI_PATTERN = "wsl_gui".freeze private_constant :WSL_GUI_PATTERN + WSL_SYSTEMD_PATTERN = "wsl_systemd".freeze + private_constant :WSL_SYSTEMD_PATTERN # Saves changes # # @param product [Hash] Selected product # @param wsl_gui_pattern [Boolean] Whether to install WSL GUI pattern - def save(product:, wsl_gui_pattern:) + def save(product:, wsl_gui_pattern:, wsl_systemd_pattern:) self.product = product self.wsl_gui_pattern = wsl_gui_pattern + self.wsl_systemd_pattern = wsl_systemd_pattern update_registration end @@ -101,6 +109,26 @@ def wsl_gui_pattern=(value) end end + # Whether the WSL systemd pattern should be installed + # + # @see ẂSLConfig + # + # @return [Boolean] + def wsl_systemd_pattern? + WSLConfig.instance.patterns.include?(WSL_SYSTEMD_PATTERN) + end + + # Sets whether to install the WSL systemd pattern + # + # @param value [Boolean] + def wsl_systemd_pattern=(value) + if value + WSLConfig.instance.patterns.push(WSL_SYSTEMD_PATTERN).uniq! + else + WSLConfig.instance.patterns.delete(WSL_SYSTEMD_PATTERN) + end + end + # Updates values stored in registration # # Those values indicates to registration what product was selected and whether the product @@ -109,7 +137,8 @@ def wsl_gui_pattern=(value) # @see Registration::Storage::InstallationOptions def update_registration yaml_product = WSLConfig.instance.product - force_registration = WSLConfig.instance.product_switched? || wsl_gui_pattern? + force_registration = WSLConfig.instance.product_switched? || + wsl_gui_pattern? || wsl_systemd_pattern? Registration::Storage::InstallationOptions.instance.yaml_product = yaml_product Registration::Storage::InstallationOptions.instance.force_registration = force_registration diff --git a/src/lib/y2firstboot/dialogs/wsl_product_selection.rb b/src/lib/y2firstboot/dialogs/wsl_product_selection.rb index 2a73c98..1552973 100644 --- a/src/lib/y2firstboot/dialogs/wsl_product_selection.rb +++ b/src/lib/y2firstboot/dialogs/wsl_product_selection.rb @@ -39,18 +39,26 @@ class WSLProductSelection < ::UI::InstallationDialog # @return [Boolean] attr_reader :wsl_gui_pattern + # Whether the WSL systemd pattern was selected + # + # @return [Boolean] + attr_reader :wsl_systemd_pattern + # Constructor # # @param products [Array] All possible products # @param default_product [Hash] Product selected by default # @param wsl_gui_pattern [Boolean] Whether WSL GUI pattern is selected by default - def initialize(products, default_product: nil, wsl_gui_pattern: false) + # @param wsl_systemd_pattern [Boolean] Whether WSL systemd pattern is selected by default + def initialize(products, default_product: nil, wsl_gui_pattern: false, + wsl_systemd_pattern: false) textdomain "firstboot" super() @products = products @product = default_product || products.first @wsl_gui_pattern = wsl_gui_pattern + @wsl_systemd_pattern = wsl_systemd_pattern end def next_handler @@ -65,6 +73,8 @@ def dialog_title _("Product Selection") end + # disable rubocop metrics as yast ui is constructed with methods + # rubocop:disable Metrics/AbcSize def dialog_content items = products.map { |p| item_for(p) } @@ -81,24 +91,40 @@ def dialog_content ), VSpacing(2), # TRANSLATORS: - Label(_("The WSL GUI pattern provides some needed packages for\n" \ - "a better experience with graphical applications in WSL.")), + Left(Label(_("The WSL GUI pattern provides some needed packages for\n" \ + "a better experience with graphical applications in WSL."))), VSpacing(1), # TRANSLATORS: check box label Left(CheckBox(Id(:wsl_gui_pattern), _("Install WSL GUI pattern (requires registration)"), - wsl_gui_pattern)) + wsl_gui_pattern)), + VSpacing(2), + # TRANSLATORS: + Left(Label(_("The WSL systemd pattern provides wsl.conf adjustment\n" \ + "and init symlink for systemd enablement in WSL."))), + VSpacing(1), + # TRANSLATORS: check box label + Left(CheckBox(Id(:wsl_systemd_pattern), + _("Install WSL systemd pattern (requires registration)"), + wsl_systemd_pattern)) ) ) end + # rubocop:enable Metrics/AbcSize def help_text - # TRANSLATORS: help text (1/2) + # TRANSLATORS: help text (1/3) _("

Select the product to use with Windows Subsystem for Linux (WSL). " \ "Some products might require registration.

") + - # TRANSLATORS: help text (2/2) - _("

To use graphical programs in WSL you need to install the WSL GUI pattern. " \ - "In that case the system needs to be registered as well.

") + # TRANSLATORS: help text (2/3) + _("

For smoother experience with graphical programs in WSL " \ + "the WSL GUI pattern provides recommended config, tools and libraries. " \ + "In that case the system needs to be registered as well.

") + + # TRANSLATORS: help text (3/3) + _("

For enablement of systemd in WSL the WSL systemd pattern provides wsl.conf " \ + "and /sbin/init adjustments. " \ + "In that case the system needs to be registered as well. " \ + "Relaunch is required to use systemd.

") end private @@ -146,6 +172,7 @@ def product_label(product) def save @wsl_gui_pattern = Yast::UI.QueryWidget(Id(:wsl_gui_pattern), :Value) + @wsl_systemd_pattern = Yast::UI.QueryWidget(Id(:wsl_systemd_pattern), :Value) selected_id = Yast::UI.QueryWidget(Id(:product_selector), :Value) @product = products.find { |p| item_id(p) == selected_id } diff --git a/test/y2firstboot/clients/wsl_product_selection_test.rb b/test/y2firstboot/clients/wsl_product_selection_test.rb index 1e4af2b..d7ced79 100755 --- a/test/y2firstboot/clients/wsl_product_selection_test.rb +++ b/test/y2firstboot/clients/wsl_product_selection_test.rb @@ -104,14 +104,16 @@ class InstallationOptions let(:dialog) do instance_double(Y2Firstboot::Dialogs::WSLProductSelection, - run: dialog_result, - product: selected_product, - wsl_gui_pattern: wsl_gui_pattern) + run: dialog_result, + product: selected_product, + wsl_gui_pattern: wsl_gui_pattern, + wsl_systemd_pattern: wsl_systemd_pattern) end let(:dialog_result) { :abort } let(:selected_product) { nil } let(:wsl_gui_pattern) { nil } + let(:wsl_systemd_pattern) { nil } let(:product_switched) { false } @@ -159,6 +161,34 @@ class InstallationOptions end end + context "if the WSL systemd pattern was selected" do + let(:wsl_systemd_pattern) { true } + + before do + Y2Firstboot::WSLConfig.instance.patterns = [] + end + + it "stores the WSL systemd pattern in the WSL config" do + subject.run + + expect(Y2Firstboot::WSLConfig.instance.patterns).to include("wsl_systemd") + end + end + + context "if the WSL systemd pattern was not selected" do + let(:wsl_systemd_pattern) { false } + + before do + Y2Firstboot::WSLConfig.instance.patterns = ["wsl_systemd"] + end + + it "does not store the WSL systemd pattern in the WSL config" do + subject.run + + expect(Y2Firstboot::WSLConfig.instance.patterns).to_not include("wsl_systemd") + end + end + it "updates the product in registration storage" do Registration::Storage::InstallationOptions.instance.yaml_product = nil @@ -170,6 +200,7 @@ class InstallationOptions context "if the product was switched" do let(:product_switched) { true } let(:wsl_gui_pattern) { false } + let(:wsl_systemd_pattern) { false } it "updates registration storage to force registration" do Registration::Storage::InstallationOptions.instance.force_registration = false @@ -200,13 +231,30 @@ class InstallationOptions context "and the WSL GUI pattern was not selected" do let(:wsl_gui_pattern) { false } - it "updates registration storage to not force registration" do - Registration::Storage::InstallationOptions.instance.force_registration = true + context "and the WSL systemd pattern was selected" do + let(:wsl_systemd_pattern) { true } - subject.run + it "updates registration storage to force registration" do + Registration::Storage::InstallationOptions.instance.force_registration = false - expect(Registration::Storage::InstallationOptions.instance.force_registration) - .to eq(false) + subject.run + + expect(Registration::Storage::InstallationOptions.instance.force_registration) + .to eq(true) + end + end + + context "and the WSL systemd pattern was not selected" do + let(:wsl_systemd_pattern) { false } + + it "updates registration storage to not force registration" do + Registration::Storage::InstallationOptions.instance.force_registration = true + + subject.run + + expect(Registration::Storage::InstallationOptions.instance.force_registration) + .to eq(false) + end end end end diff --git a/test/y2firstboot/dialogs/wsl_product_selection_test.rb b/test/y2firstboot/dialogs/wsl_product_selection_test.rb index 248be2c..0516a57 100755 --- a/test/y2firstboot/dialogs/wsl_product_selection_test.rb +++ b/test/y2firstboot/dialogs/wsl_product_selection_test.rb @@ -43,7 +43,9 @@ def find_widget(regexp, content) subject do described_class.new(products, - default_product: default_product, wsl_gui_pattern: wsl_gui_pattern) + default_product: default_product, + wsl_gui_pattern: wsl_gui_pattern, + wsl_systemd_pattern: wsl_systemd_pattern) end let(:products) { [sles, sled] } @@ -52,6 +54,7 @@ def find_widget(regexp, content) let(:default_product) { sled } let(:wsl_gui_pattern) { false } + let(:wsl_systemd_pattern) { false } let(:installed_product) { double(Y2Packager::Resolvable, name: "SLES", version_version: "15.4") } before do @@ -80,6 +83,12 @@ def find_widget(regexp, content) expect(widget).to_not be_nil end + it "shows a check box for selecting the WSL systemd pattern" do + widget = find_widget(:wsl_systemd_pattern, subject.send(:dialog_content)) + + expect(widget).to_not be_nil + end + it "automatically selects the default product" do widget = find_widget(/SLED/, subject.send(:dialog_content)) @@ -105,12 +114,34 @@ def find_widget(regexp, content) expect(widget.params.last).to eq(false) end end + + context "when WSL systemd pattern is indicated as selected" do + let(:wsl_systemd_pattern) { true } + + it "selects WSL systemd pattern checkbox by default" do + widget = find_widget(:wsl_systemd_pattern, subject.send(:dialog_content)) + + expect(widget.params.last).to eq(true) + end + end + + context "when WSL systemd pattern is not indicated as selected" do + let(:wsl_systemd_pattern) { false } + + it "does not select WSL systemd pattern checkbox by default" do + widget = find_widget(:wsl_systemd_pattern, subject.send(:dialog_content)) + + expect(widget.params.last).to eq(false) + end + end end describe "#next_handler" do before do allow(Yast::UI).to receive(:QueryWidget).and_call_original allow(Yast::UI).to receive(:QueryWidget).with(Id(:wsl_gui_pattern), :Value).and_return(true) + allow(Yast::UI).to receive(:QueryWidget).with(Id(:wsl_systemd_pattern), :Value) + .and_return(true) allow(Yast::UI).to receive(:QueryWidget).with(Id(:product_selector), :Value) .and_return("SLES:15.4") end @@ -123,6 +154,14 @@ def find_widget(regexp, content) expect(subject.wsl_gui_pattern).to eq(true) end + it "saves whether the WSL GUI pattern checkbox was selected" do + expect(subject.wsl_systemd_pattern).to eq(false) + + subject.next_handler + + expect(subject.wsl_systemd_pattern).to eq(true) + end + it "saves the selected product" do expect(subject.product).to eq(sled)