From 8d12d0f3030beb1bb7671b24594629115b4be945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Alejandro=20Anderssen=20Gonz=C3=A1lez?= Date: Tue, 19 May 2020 15:12:03 +0100 Subject: [PATCH] Moved auto client under y2network namespace --- src/clients/lan_auto.rb | 199 +----------------- src/lib/network/network_autoyast.rb | 11 +- src/lib/y2network/autoinst/config.rb | 2 +- .../autoinst_profile/networking_section.rb | 4 +- src/lib/y2network/clients/auto.rb | 170 +++++++++++++++ src/modules/Lan.rb | 13 +- test/lan_auto_test.rb | 48 ----- test/y2network/clients/auto_test.rb | 126 +++++++++++ 8 files changed, 312 insertions(+), 261 deletions(-) create mode 100644 src/lib/y2network/clients/auto.rb delete mode 100755 test/lan_auto_test.rb create mode 100755 test/y2network/clients/auto_test.rb diff --git a/src/clients/lan_auto.rb b/src/clients/lan_auto.rb index e70b25794..d088e0a32 100644 --- a/src/clients/lan_auto.rb +++ b/src/clients/lan_auto.rb @@ -1,198 +1,3 @@ -# *************************************************************************** -# -# Copyright (c) 2012 Novell, Inc. -# All Rights Reserved. -# -# 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 Novell, Inc. -# -# To contact Novell about this file by physical or electronic mail, -# you may find current contact information at www.novell.com -# -# ************************************************************************** +require "y2network/clients/auto" -require "network/network_autoyast" - -module Yast - # Client providing autoyast functionality - class LanAutoClient < Client - include Yast::Logger - - def main - Yast.import "UI" - - textdomain "network" - - Builtins.y2milestone("----------------------------------------") - Builtins.y2milestone("Lan autoinst client started") - - Yast.import "Lan" - Yast.import "Progress" - Yast.import "Map" - Yast.import "NetworkInterfaces" - Yast.import "LanItems" - Yast.include self, "network/lan/wizards.rb" - Yast.include self, "network/routines.rb" - - @func = "" - @param = {} - - # Check arguments - if Ops.greater_than(Builtins.size(WFM.Args), 0) && - Ops.is_string?(WFM.Args(0)) - @func = Convert.to_string(WFM.Args(0)) - if Ops.greater_than(Builtins.size(WFM.Args), 1) && - Ops.is_map?(WFM.Args(1)) - @param = Convert.to_map(WFM.Args(1)) - end - end - - Builtins.y2milestone("Lan autoinst callback: #{@func}") - - if @func == "Summary" - @ret = Lan.Summary("summary") - elsif @func == "Reset" - Lan.Import({}) - Yast::Lan.clear_configs - @ret = {} - elsif @func == "Change" - Yast::Lan.add_config(:yast, Y2Network::Config.from(:defaults)) unless Yast::Lan.yast_config - @ret = LanAutoSequence("") - elsif @func == "Import" - @new = Lan.FromAY(@param) - # see bnc#498993 - # in case keep_install_network is set to true (in AY) - # we'll keep values from installation - # and merge with XML data (bnc#712864) - @new = NetworkAutoYast.instance.merge_configs(@new) if @new["keep_install_network"] - - Lan.Import(@new) - @ret = true - elsif @func == "Read" - @progress_orig = Progress.set(false) - @ret = Lan.Read(:nocache) - Progress.set(@progress_orig) - elsif @func == "Packages" - @ret = Lan.AutoPackages - elsif @func == "SetModified" - @ret = Lan.SetModified - elsif @func == "GetModified" - @ret = Lan.Modified - elsif @func == "Export" - @settings2 = Lan.Export - Builtins.y2debug("settings: %1", @settings2) - @autoyast = ToAY(@settings2) - @ret = deep_copy(@autoyast) - elsif @func == "Write" - @progress_orig = Progress.set(false) - - result = Lan.WriteOnly - Builtins.y2error("Writing lan config failed") if !result - @ret &&= result - timeout = Lan.autoinst.ip_check_timeout || -1 - - if (timeout >= 0) && Lan.isAnyInterfaceDown - Builtins.y2debug("timeout %1", timeout) - error_text = _("Configuration Error: uninitialized interface.") - timeout == 0 ? Popup.Error(error_text) : Popup.TimedError(error_text, timeout) - end - - Progress.set(@progress_orig) - else - Builtins.y2error("unknown function: %1", @func) - @ret = false - end - - Builtins.y2milestone("Lan auto finished (#{@ret})") - Builtins.y2milestone("----------------------------------------") - @ret - end - - # Convert data from native network to autoyast for XML - # @param [Hash] settings native network settings - # @return [Hash] autoyast network settings - def ToAY(settings) - settings = deep_copy(settings) - interfaces = settings["interfaces"] || [] - Builtins.y2milestone("interfaces: #{interfaces.inspect})") - net_udev = settings["net-udev"] || [] - Builtins.y2milestone("net-udev: #{net_udev.inspect})") - - # Modules - s390_devices = settings["s390-devices"] || [] - Builtins.y2milestone("s390-devices: #{s390_devices.inspect})") - - modules = [] - Builtins.foreach(Ops.get_map(settings, "hwcfg", {})) do |device, mod| - newmap = {} - Ops.set(newmap, "device", device) - Ops.set(newmap, "module", Ops.get_string(mod, "MODULE", "")) - Ops.set(newmap, "options", Ops.get_string(mod, "MODULE_OPTIONS", "")) - modules = Builtins.add(modules, newmap) - end - - config = Ops.get_map(settings, "config", {}) - dhcp = Ops.get_map(config, "dhcp", {}) - dhcp_hostname = Ops.get_boolean(dhcp, "DHCLIENT_SET_HOSTNAME", false) - dns = Ops.get_map(settings, "dns", {}) - Ops.set(dns, "dhcp_hostname", dhcp_hostname) - dhcpopts = {} - if Builtins.haskey(dhcp, "DHCLIENT_HOSTNAME_OPTION") - Ops.set( - dhcpopts, - "dhclient_hostname_option", - Ops.get_string(dhcp, "DHCLIENT_HOSTNAME_OPTION", "AUTO") - ) - end - if Builtins.haskey(dhcp, "DHCLIENT_ADDITIONAL_OPTIONS") - Ops.set( - dhcpopts, - "dhclient_additional_options", - Ops.get_string(dhcp, "DHCLIENT_ADDITIONAL_OPTIONS", "") - ) - end - if Builtins.haskey(dhcp, "DHCLIENT_CLIENT_ID") - Ops.set( - dhcpopts, - "dhclient_client_id", - Ops.get_string(dhcp, "DHCLIENT_CLIENT_ID", "") - ) - end - - ret = {} - Ops.set(ret, "managed", Ops.get_boolean(settings, "managed", false)) - if Builtins.haskey(settings, "ipv6") - Ops.set(ret, "ipv6", Ops.get_boolean(settings, "ipv6", true)) - end - Ops.set( - ret, - "keep_install_network", - Ops.get_boolean(settings, "keep_install_network", true) - ) - Ops.set(ret, "modules", modules) if Ops.greater_than(Builtins.size(modules), 0) - Ops.set(ret, "dns", dns) if Ops.greater_than(Builtins.size(dns), 0) - Ops.set(ret, "dhcp_options", dhcpopts) if Ops.greater_than(Builtins.size(dhcpopts), 0) - if Ops.greater_than( - Builtins.size(Ops.get_map(settings, "routing", {})), - 0 - ) - Ops.set(ret, "routing", Ops.get_map(settings, "routing", {})) - end - Ops.set(ret, "interfaces", interfaces) if Ops.greater_than(Builtins.size(interfaces), 0) - Ops.set(ret, "s390-devices", s390_devices) if Ops.greater_than(Builtins.size(s390_devices), 0) - Ops.set(ret, "net-udev", net_udev) if Ops.greater_than(Builtins.size(net_udev), 0) - deep_copy(ret) - end - end -end - -Yast::LanAutoClient.new.main +Y2Network::Clients::Auto.new.run diff --git a/src/lib/network/network_autoyast.rb b/src/lib/network/network_autoyast.rb index 4d8376f31..a3223b789 100644 --- a/src/lib/network/network_autoyast.rb +++ b/src/lib/network/network_autoyast.rb @@ -103,16 +103,15 @@ def set_network_service # Initializates NICs setup according AY profile # - # If the installer is running in 1st stage mode only, then the configuration - # is also written + # If the network was already written before the proposal it returns without + # touching it # - # @param [Boolean] write forces instant writing of the configuration - # @return [Boolean] true when configuration was present and loaded from the profile - def configure_lan(write: false) + # @return [Boolean] true when written + def configure_lan log.info("NetworkAutoYast: Lan configuration") return false if Lan.autoinst.before_proposal - result = Lan.WriteOnly + Lan.WriteOnly end # Takes care of activate s390 devices from the profile declaration diff --git a/src/lib/y2network/autoinst/config.rb b/src/lib/y2network/autoinst/config.rb index ed751b6d3..6df715751 100644 --- a/src/lib/y2network/autoinst/config.rb +++ b/src/lib/y2network/autoinst/config.rb @@ -19,7 +19,7 @@ module Y2Network module Autoinst - # This class is responsible of storing network settings that are only + # This class is responsible of storing network settings that are only # relevant to the autoinstallation proccess. class Config # @return [Boolean] controls whether the network configuration should be diff --git a/src/lib/y2network/autoinst_profile/networking_section.rb b/src/lib/y2network/autoinst_profile/networking_section.rb index ca30be0fa..add23465b 100644 --- a/src/lib/y2network/autoinst_profile/networking_section.rb +++ b/src/lib/y2network/autoinst_profile/networking_section.rb @@ -35,7 +35,6 @@ module AutoinstProfile # # @see RoutingSection class NetworkingSection - # @return [Boolean] attr_accessor :setup_before_proposal # @return [Boolean] @@ -45,7 +44,6 @@ class NetworkingSection # @return [Integer] attr_accessor :strict_ip_check_timeout - # @return [RoutingSection] attr_accessor :routing # @return [DNSSection] @@ -107,7 +105,7 @@ def to_hashes "dns" => dns.to_hashes, "interfaces" => interfaces.to_hashes, "net-udev" => udev_rules.to_hashes, - "s390-devices" => s390_devices.to_hashes, + "s390-devices" => s390_devices.to_hashes } end end diff --git a/src/lib/y2network/clients/auto.rb b/src/lib/y2network/clients/auto.rb new file mode 100644 index 000000000..482d57f4d --- /dev/null +++ b/src/lib/y2network/clients/auto.rb @@ -0,0 +1,170 @@ +# Copyright (c) [2020] SUSE LLC +# +# All Rights Reserved. +# +# 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 LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. +require "yast" +require "installation/auto_client" + +Yast.import "Lan" +Yast.import "Progress" +Yast.import "Map" +Yast.import "LanItems" + +module Y2Network + module Clients + # This class is responsible of AutoYaST network configuration + class Auto < ::Installation::AutoClient + # Constructor + def initialize + textdomain "network" + + Yast.include self, "network/lan/wizards.rb" + end + + def read + @progress_orig = Yast::Progress.set(false) + ret = Yast::Lan.Read(:nocache) + Yast::Progress.set(@progress_orig) + ret + end + + def write + @progress_orig = Yast::Progress.set(false) + + result = Yast::Lan.WriteOnly + log.error("Writing lan config failed") if !result + @ret &&= result + timeout = Yast::Lan.autoinst.ip_check_timeout || -1 + + if (timeout >= 0) && Lan.isAnyInterfaceDown + Builtins.y2debug("timeout %1", timeout) + error_text = _("Configuration Error: uninitialized interface.") + (timeout == 0) ? Popup.Error(error_text) : Popup.TimedError(error_text, timeout) + end + + Yast::Progress.set(@progress_orig) + end + + def summary + Yast::Lan.Summary("summary") + end + + def reset + Yast::Lan.Import({}) + Yast::Lan.clear_configs + {} + end + + def change + if !Yast::Lan.yast_config + Yast::Lan.add_config(:yast, Y2Network::Config.new(:source, :config)) + end + LanAutoSequence("") + end + + def import(profile) + modified_profile = Yast::Lan.FromAY(profile) + + # see bnc#498993 + # in case keep_install_network is set to true (in AY) + # we'll keep values from installation + # and merge with XML data (bnc#712864) + if modified_profile.fetch("keep_install_network", true) + modified_profile = Yast::NetworkAutoYast.instance.merge_configs(modified_profile) + end + + Yast::Lan.Import(modified_profile) + true + end + + def packages + Yast::Lan.AutoPackages + end + + def modified + Yast::Lan.SetModified + end + + def modified? + Yast::Lan.Modified + end + + def export + raw_config = Yast::Lan.Export + log.debug("settings: #{raw_config.inspect}") + adapt_for_autoyast(raw_config) + end + + private + + def merge_current_config? + !!Yast::Lan.autoinst.keep_install_network + end + + # Convert data from native network to autoyast for XML + # @param [Hash] settings native network settings + # @return [Hash] autoyast network settings + def adapt_for_autoyast(settings) + settings = deep_copy(settings) + interfaces = settings["interfaces"] || [] + log.info("interfaces: #{interfaces.inspect}") + net_udev = settings["net-udev"] || [] + log.info("net-udev: #{net_udev.inspect}") + + # Modules + s390_devices = settings["s390-devices"] || [] + log.info("s390-devices: #{s390_devices.inspect}") + + modules = [] + settings.fetch("hwcfg", {}).each do |device, mod| + newmap = { "device" => device } + newmap["module"] = mod.fetch("MODULE", "") + newmap["options"] = mod.fetch("MODULE_OPTIONS", "") + modules << newmap + end + + config = settings.fetch("config", {}) + dhcp = config.fetch("dhcp", {}) + dhcp_hostname = dhcp.fetch("DHCLIENT_SET_HOSTNAME", false) + dns = settings.fetch("dns", {}) + dns["dhcp_hostname"] = dhcp_hostname + dhcpopts = {} + if dhcp.keys.include?("DHCLIENT_HOSTNAME_OPTION") + dhcpopts["dhclient_hostname_option"] = dhcp.fetch("DHCLIENT_HOSTNAME_OPTION", "AUTO") + end + if dhcp.keys.include?("DHCLIENT_ADDITIONAL_OPTIONS") + dhcpopts["dhclient_additional_options"] = dhcp.fetch("DHCLIENT_ADDITIONAL_OPTIONS", "") + end + if dhcp.keys.include?("DHCLIENT_CLIENT_ID") + dhcpopts["dhclient_client_id"] = dhcp.fetch("DHCLIENT_CLIENT_ID", "") + end + + ret = { "managed" => settings.fetch("managed", false) } + ret["ipv6"] = settings.fetch("ipv6", true) if settings.keys.include?("ipv6") + ret["keep_install_network"] = settings.fetch("keep_install_network", true) + ret["modules"] = modules unless modules.empty? + ret["dns"] = dns unless dns.empty? + ret["dhcp_options"] = dhcpopts unless dhcpopts.empty? + ret["routing"] = settings["routing"] unless settings.fetch("routing", {}).empty? + ret["interfaces"] = interfaces unless interfaces.empty? + ret["s390-devices"] = s390_devices unless s390_devices.empty? + ret["net-udev"] = net_udev unless net_udev.empty? + ret.dup + end + end + end +end diff --git a/src/modules/Lan.rb b/src/modules/Lan.rb index 819e72736..d970328ee 100644 --- a/src/modules/Lan.rb +++ b/src/modules/Lan.rb @@ -110,7 +110,7 @@ def main # @return [Boolean] attr_accessor :write_only # @return [Autoinst::Config] - attr_accessor :autoinst + attr_writer :autoinst #------------------ # GLOBAL FUNCTIONS @@ -675,8 +675,9 @@ def Import(settings) end # Export data. - # They need to be passed through {LanAutoClient#ToAY} to become - # what networking.rnc describes. + # They need to be converted to become what networking.rnc describes. + # @see Y2Network::Clients::Auto.adapt_for_autoyast + # # Most prominently, instead of a flat list called "interfaces" # we export a 2-level map of typed "devices" # @return dumped settings @@ -864,10 +865,10 @@ def autoinst_config(section) return unless autoinst_settings?(section) Y2Network::Autoinst::Config.new( - before_proposal: section.setup_before_proposal, - start_immediately: section.start_immediately, + before_proposal: section.setup_before_proposal, + start_immediately: section.start_immediately, keep_install_network: section.keep_install_network, - ip_check_timeout: section.strict_ip_check_timeout + ip_check_timeout: section.strict_ip_check_timeout ) end diff --git a/test/lan_auto_test.rb b/test/lan_auto_test.rb deleted file mode 100755 index a715d9188..000000000 --- a/test/lan_auto_test.rb +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env rspec - -# Copyright (c) [2019] SUSE LLC -# -# All Rights Reserved. -# -# 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 LLC. -# -# To contact SUSE LLC about this file by physical or electronic mail, you may -# find current contact information at www.suse.com. - -require_relative "test_helper" - -require "yast" -require_relative "../src/clients/lan_auto" - -describe Yast::LanAutoClient do - describe "#main" do - before do - allow(Yast::WFM).to receive(:Args).with(no_args).and_return([func]) - allow(Yast::WFM).to receive(:Args).with(0).and_return(func) - end - - context "when func is GetModified" do - let(:func) { "GetModified" } - - it "returns true if Lan.GetModified is true" do - expect(Yast::Lan).to receive(:Modified).and_return(true) - expect(subject.main).to eq(true) - end - - it "returns false if Lan.GetModified is false" do - expect(Yast::Lan).to receive(:Modified).and_return(false) - expect(subject.main).to eq(false) - end - end - end -end diff --git a/test/y2network/clients/auto_test.rb b/test/y2network/clients/auto_test.rb new file mode 100755 index 000000000..d43c19070 --- /dev/null +++ b/test/y2network/clients/auto_test.rb @@ -0,0 +1,126 @@ +#!/usr/bin/env rspec +# Copyright (c) [2020] SUSE LLC +# +# All Rights Reserved. +# +# 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 LLC. +# +# To contact SUSE LLC about this file by physical or electronic mail, you may +# find current contact information at www.suse.com. + +require_relative "../../test_helper" +require "y2network/clients/auto" + +describe Y2Network::Clients::Auto do + let(:network_autoyast) { Yast::NetworkAutoYast.instance } + + describe "#reset" do + it "clears Yast::Lan internal state" do + allow(Yast::Lan).to receive(:Import).with({}) + expect(Yast::Lan).to receive(:clear_configs) + subject.reset + end + end + + describe "#read" do + it "forces a Lan read" do + expect(Yast::Lan).to receive(:Read).with(:nocache) + subject.read + end + end + + describe "#import" do + let(:profile) { { "keep_install_network" => false } } + let(:from_ay_profile) { profile.dup } + + before do + allow(Yast::Lan).to receive(:Import) + allow(Yast::Lan).to receive(:FromAY).with(profile).and_return(from_ay_profile) + end + + it "prepares the given profile to be imported" do + expect(Yast::Lan).to receive(:FromAY).with(profile).and_return(from_ay_profile) + + subject.import(profile) + end + + it "imports the given profile" do + expect(Yast::Lan).to receive(:Import).with(from_ay_profile) + + subject.import(profile) + end + + context "unless the profile specifies that the current config should be ignored" do + let(:profile) { { "keep_install_network" => true } } + + it "merges the given profile with the current network config before import" do + expect(network_autoyast).to receive(:merge_configs).with(from_ay_profile) + + subject.import(profile) + end + end + + context "when the profile specifies that the current config should be ignored" do + it "does not merge the given profile with the current network config before import" do + expect(network_autoyast).to_not receive(:merge_configs) + + subject.import(profile) + end + end + end + + describe "#export" do + it "exports the current network configuration prepared for AutoYaST" do + expect(Yast::Lan).to receive(:Export).and_return(:exported_config) + expect(subject).to receive(:adapt_for_autoyast).with(:exported_config).and_return(:ay_config) + expect(subject.export).to eql(:ay_config) + end + end + + describe "#summary" do + let(:config_summary) { "config" } + + it "returns a text summary of the autoyast config network configuration" do + allow(Yast::Lan).to receive(:Summary).with("summary").and_return(config_summary) + + expect(subject.summary).to eql(config_summary) + end + end + + describe "#packages" do + let(:packages) { { "install" => ["wpa_supplicant"], "remove" => [] } } + + it "returns a hash with the packages that need to be installed and removed" do + allow(Yast::Lan).to receive(:AutoPackages).and_return(packages) + expect(subject.packages).to eql(packages) + end + end + + describe "#modified" do + it "sets the network config as modified" do + expect(Yast::Lan).to receive(:SetModified) + + subject.modified + end + end + + describe "#modified?" do + let(:modified) { :true_or_false } + + it "returns whether lan configuration has been modified or not" do + allow(Yast::Lan).to receive(:Modified).and_return(modified) + + expect(subject.modified?).to eql(modified) + end + end +end