Skip to content

Commit

Permalink
Merge pull request #520 from mchf/sle15-ay-network-in-first-stage
Browse files Browse the repository at this point in the history
[Sle15] AY setup written in first stage
  • Loading branch information
mchf committed Jul 21, 2017
2 parents 465fe0b + b9c5e1a commit 02d8e75
Show file tree
Hide file tree
Showing 11 changed files with 445 additions and 280 deletions.
8 changes: 8 additions & 0 deletions package/yast2-network.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
-------------------------------------------------------------------
Fri Jul 11 09:40:11 UTC 2017 - mfilka@suse.com

- bnc#1049814
- Moving network setup in AY into first stage completely when
the second stage is disabled.
- 3.3.3

-------------------------------------------------------------------
Mon Jul 10 15:03:09 UTC 2017 - jreidinger@suse.com

Expand Down
2 changes: 1 addition & 1 deletion package/yast2-network.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


Name: yast2-network
Version: 3.3.2
Version: 3.3.3
Release: 0
BuildArch: noarch

Expand Down
127 changes: 1 addition & 126 deletions src/clients/lan_auto.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def main
elsif @func == "Change"
@ret = LanAutoSequence("")
elsif @func == "Import"
@new = FromAY(@param)
@new = Lan.FromAY(@param)
# see bnc#498993
# in case keep_install_network is set to true (in AY)
# we'll keep values from installation
Expand Down Expand Up @@ -124,131 +124,6 @@ def main
@ret
end

# If there's key in m, upcase key and assign the value to ret
# @return ret
def UpcaseCondSet(ret, m, key)
ret = deep_copy(ret)
m = deep_copy(m)
if Builtins.haskey(m, key)
Ops.set(ret, Builtins.toupper(key), Ops.get(m, key))
end
deep_copy(ret)
end

# Convert data from autoyast to structure used by module.
# @param [Hash] input autoyast settings
# @return native network settings
def FromAY(input)
input = deep_copy(input)
Builtins.y2debug("input %1", input)

ifaces = []
Builtins.foreach(Ops.get_list(input, "interfaces", [])) do |interface|
iface = {}
Builtins.foreach(interface) do |key, value|
if key == "aliases"
Builtins.foreach(
Convert.convert(
value,
from: "any",
to: "map <string, map <string, any>>"
)
) do |k, v|
# replace "alias0" to "0" (bnc#372687)
t = Convert.convert(
value,
from: "any",
to: "map <string, any>"
)
Ops.set(t, Ops.get_string(v, "LABEL", ""), Ops.get_map(t, k, {}))
t = Builtins.remove(t, k)
value = deep_copy(t)
end
end
Ops.set(iface, key, value)
end
ifaces = Builtins.add(ifaces, iface)
end
Ops.set(input, "interfaces", ifaces)

interfaces = Builtins.listmap(Ops.get_list(input, "interfaces", [])) do |interface|
# input: list of items $[ "device": "d", "foo": "f", "bar": "b"]
# output: map of items "d": $["FOO": "f", "BAR": "b"]
new_interface = {}
# uppercase map keys
newk = nil
interface = Builtins.mapmap(interface) do |k, v|
newk = if k == "aliases"
"_aliases"
else
Builtins.toupper(k)
end
{ newk => v }
end
Builtins.foreach(interface) do |k, v|
Ops.set(new_interface, k, v) if v != "" && k != "DEVICE"
end
new_device = Ops.get_string(interface, "DEVICE", "")
{ new_device => new_interface }
end

# split to a two level map like NetworkInterfaces
devices = {}

Builtins.foreach(interfaces) do |devname, if_data|
# devname can be in old-style fashion (eth-bus-<pci_id>). So, convert it
devname = LanItems.getDeviceName(devname)
type = NetworkInterfaces.GetType(devname)
d = Ops.get(devices, type, {})
Ops.set(d, devname, if_data)
Ops.set(devices, type, d)
end

hwcfg = {}
if Ops.greater_than(Builtins.size(Ops.get_list(input, "modules", [])), 0)
hwcfg = Builtins.listmap(Ops.get_list(input, "modules", [])) do |mod|
options = Ops.get_string(mod, "options", "")
module_name = Ops.get_string(mod, "module", "")
start_mode = Ops.get_string(mod, "startmode", "auto")
device_name = Ops.get_string(mod, "device", "")
module_data = {
"MODULE" => module_name,
"MODULE_OPTIONS" => options,
"STARTMODE" => start_mode
}
{ device_name => module_data }
end
end

Ops.set(input, "devices", devices)
Ops.set(input, "hwcfg", hwcfg)

# DHCP:: config: some of it is in the DNS part of the profile
dhcp = {}
dhcpopts = Ops.get_map(input, "dhcp_options", {})
dns = Ops.get_map(input, "dns", {})

if Builtins.haskey(dns, "dhcp_hostname")
Ops.set(
dhcp,
"DHCLIENT_SET_HOSTNAME",
Ops.get_boolean(dns, "dhcp_hostname", false)
)
end

dhcp = UpcaseCondSet(dhcp, dhcpopts, "dhclient_client_id")
dhcp = UpcaseCondSet(dhcp, dhcpopts, "dhclient_additional_options")
dhcp = UpcaseCondSet(dhcp, dhcpopts, "dhclient_hostname_option")

Ops.set(input, "config", "dhcp" => dhcp)
if !Ops.get(input, "strict_IP_check_timeout").nil?
Ops.set(input, ["config", "config"], "CHECK_DUPLICATE_IP" => true)
end

Builtins.y2milestone("input=%1", input)
deep_copy(input)
end

# Convert data from native network to autoyast for XML
# @param [Hash] settings native network settings
# @return [Hash] autoyast network settings
Expand Down
24 changes: 22 additions & 2 deletions src/clients/save_network.rb
Original file line number Diff line number Diff line change
Expand Up @@ -259,16 +259,36 @@ def configure_dns
DNS.create_hostname_link
end

# Creates target's /etc/hosts configuration
#
# It uses hosts' configuration as defined in AY profile (if any) or
# proceedes according the proposal
def configure_hosts
configured = false
configured = NetworkAutoYast.instance.configure_hosts if Mode.autoinst
NetworkAutoconfiguration.instance.configure_hosts if !configured
end

# Invokes configuration of parts which are in charge of Lan module
#
# Currently it handles just AutoYaST installation. It just exits in case
# of common installation as there currently is nothing to do.
def configure_lan
return if !Mode.autoinst

NetworkAutoYast.instance.configure_lan
end

# It does an automatic configuration of installed system
#
# Basically, it runs several proposals.
def configure_target
NetworkAutoconfiguration.instance.configure_virtuals

configure_dns
configure_lan

# this depends on DNS configuration
NetworkAutoconfiguration.instance.configure_hosts
configure_hosts

set_network_service

Expand Down
107 changes: 90 additions & 17 deletions src/lib/network/network_autoyast.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def initialize
Yast.import "Lan"
Yast.import "LanItems"
Yast.import "Linuxrc"
Yast.import "Host"
Yast.import "Routing"
end

# Merges existing config from system into given configuration map
Expand Down Expand Up @@ -104,26 +106,39 @@ def set_network_service
NetworkService.EnableDisableNow
end

# Initializates DNS setup according AY profile
# Initializates NICs setup according AY profile
#
# FIXME: it currently doesn't write DNS configuration. It is used for initialization
# of DNS setup according AY profile in 1st stage as part of network setup was moved
# here already and some parts of network configuration needs to know it. DNS write
# is still done in 2nd stage.
# If the installer is running in 1st stage mode only, then the configuration
# is also written
#
# @param [Boolean] write forces instant writing of the configuration
# @return [Boolean] true when configuration was present and loaded from the profile
def configure_dns
ay_dns_config = ay_networking_section["dns"]
def configure_lan(write: false)
log.info("NetworkAutoYast: Lan configuration")

return false if !ay_dns_config
ay_configuration = Lan.FromAY(ay_networking_section)
ay_configuration = NetworkAutoYast.instance.merge_configs(ay_configuration) if keep_net_config?

DNS.Import(ay_dns_config)
configure_submodule(Lan, ay_configuration, write: write)
end

log.info("NetworkAutoYast: DNS / Hostname configuration")
log.info("dhcp hostname: #{DNS.dhcp_hostname}")
log.info("write hostname: #{DNS.write_hostname}")
# Initializates /etc/hosts according AY profile
#
# If the installer is running in 1st stage mode only, then the configuration
# is also written
#
# @param [Boolean] write forces instant writing of the configuration
# @return [Boolean] true when configuration was present and loaded from the profile
def configure_hosts(write: false)
log.info("NetworkAutoYast: Hosts configuration")

true
hosts_config = (ay_host_section["hosts"] || {}).map do |host|
# we need to guarantee order of the items here
[host["host_address"] || "", host["names"] || []]
end
hosts_config = hosts_config.to_h.delete_if { |k, v| k.empty? || v.empty? }

configure_submodule(Host, "hosts" => hosts_config, write: write)
end

# Checks if the profile asks for keeping installation network configuration
Expand Down Expand Up @@ -206,16 +221,53 @@ def merge_routing(instsys_routing, ay_routing)
instsys_routing.merge(ay_routing)
end

# Returns networking section of current AY profile
def ay_networking_section
# Returns current AY profile in the internal representation
#
# @return [Hash] hash representing current profile or empty hash
def ay_current_profile
Yast.import "Profile"

ay_profile = Profile.current

return {} if ay_profile.nil? || ay_profile.empty?
return {} if ay_profile["networking"].nil?
ay_profile
end

# Returns networking section of current AY profile
def ay_networking_section
return {} if ay_current_profile["networking"].nil?

ay_current_profile["networking"]
end

# Returns global section of current AY profile
def ay_general_section
return {} if ay_current_profile["general"].nil?

ay_profile["networking"]
ay_current_profile["general"]
end

# Returns host section of the current AY profile
#
# Note that autoyast transforms the host's subsection
# into:
# {
# hosts => [
# # first <host_entry>
# {
# "host_address" => <ip>,
# "names" => [list, of, names]
# }
# # second <host_entry>
# ...
# ]
# }
#
# return <Hash> with hosts configuration
def ay_host_section
return {} if ay_current_profile["host"].nil?

ay_current_profile["host"]
end

# Checks if the udev rule is valid for renaming a NIC
Expand Down Expand Up @@ -265,5 +317,26 @@ def assign_udevs_to_devs(udev_rules)
LanItems.rename(name_to)
end
end

# Configures given yast submodule according AY configuration
#
# It takes data from AY profile transformed into a format expected by the YaST
# sub module's Import method.
#
# It imports the profile, configures the module and writes the configuration.
# Writing the configuration is optional when second stage is available and mandatory
# when running autoyast installation with first stage only.
def configure_submodule(yast_module, ay_config, write: false)
return false if !ay_config

yast_module.Import(ay_config)

write ||= !ay_general_section.fetch("mode", "second_stage" => true)["second_stage"]
log.info("Write configuration instantly: #{write}")

yast_module.Write(gui: false) if write

true
end
end
end
Loading

0 comments on commit 02d8e75

Please sign in to comment.