Skip to content

Commit

Permalink
Merge pull request #1161 from yast/better-readers
Browse files Browse the repository at this point in the history
Better readers
  • Loading branch information
imobachgs committed Feb 5, 2021
2 parents 267cb63 + 7f2daf3 commit e2e506f
Show file tree
Hide file tree
Showing 11 changed files with 405 additions and 172 deletions.
25 changes: 25 additions & 0 deletions src/lib/y2network/config.rb
Expand Up @@ -264,6 +264,31 @@ def backend=(id)
@backend = Y2Network::Backend.all.find { |b| b.id == id }
end

# Updates configuration section
#
# This method returns a new instance of Config, leaving the received
# as it is.
#
# @example Update interfaces list
# config.update(interfaces: InterfacesCollection.new)
#
# @param changes [Hash<Symbol,Object>] A hash where the keys are the
# sections to update and the values are the new values
# @return [Y2Network::Config]
def update(changes = {})
self.class.new(
interfaces: changes[:interfaces] || interfaces,
connections: changes[:connections] || connections,
s390_devices: changes[:s390_devices] || s390_devices,
drivers: changes[:drivers] || drivers,
routing: changes[:routing] || routing,
dns: changes[:dns] || dns,
hostname: changes[:hostname] || hostname,
source: changes[:source] || source,
backend: changes[:backend] || backend
)
end

alias_method :eql?, :==

private
Expand Down
43 changes: 33 additions & 10 deletions src/lib/y2network/config_reader.rb
Expand Up @@ -16,18 +16,41 @@
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require "yast"

module Y2Network
module ConfigReader
# Config reader for a given source
# This class is responsible for reading the configuration from the system
#
# It implements a {#config} method which returns a configuration object
# containing the information from the corresponding backend.
#
# It is expect that a configuration reader exists for each supported backend
# by inheriting from this class.
class ConfigReader
include Yast::Logger

class << self
# Returns a configuration reader for a given source
#
# @param source [Symbol] Source name (e.g., :wicked)
# @param opts [Array<Object>] Reader options
# @return [Y2Network::Autoinst::ConfigReader,Y2Network::Wicked::ConfigReader]
def for(source, *opts)
require "y2network/#{source}/config_reader"
modname = source.to_s.split("_").map(&:capitalize).join
klass = Y2Network.const_get("#{modname}::ConfigReader")
klass.new(*opts)
end
end

def initialize(_opts = {}); end

# Returns the configuration from the given backend
#
# @param source [Symbol] Source name (e.g., :wicked)
# @param opts [Array<Object>] Reader options
# @return [Y2Network::Autoinst::ConfigReader,Y2Network::Wicked::ConfigReader]
def self.for(source, *opts)
require "y2network/#{source}/config_reader"
modname = source.to_s.split("_").map(&:capitalize).join
klass = Y2Network.const_get("#{modname}::ConfigReader")
klass.new(*opts)
# @return [Y2Network::Config] Network configuration
def config
Y2Network::Config.new
end
end
end
8 changes: 8 additions & 0 deletions src/lib/y2network/interfaces_collection.rb
Expand Up @@ -197,5 +197,13 @@ def free_names(prefix, count)
return result if result.size == count
end
end

# Returns a new collection including elements from both collections
#
# @param other [InterfacesCollection] Other interfaces collection
# @return [InterfacesCollection] New interfaces collection
def +(other)
self.class.new(to_a + other.to_a)
end
end
end
131 changes: 99 additions & 32 deletions src/lib/y2network/wicked/config_reader.rb
Expand Up @@ -18,64 +18,145 @@
# find current contact information at www.suse.com.
require "yast"
require "cfa/sysctl_config"
require "y2network/config"
require "y2network/config_reader"
require "y2network/interface"
require "y2network/routing"
require "y2network/routing_table"
require "cfa/routes_file"
require "y2network/wicked/dns_reader"
require "y2network/wicked/hostname_reader"
require "y2network/wicked/interfaces_reader"
require "y2network/interfaces_collection"
require "y2network/wicked/connection_configs_reader"

Yast.import "NetworkInterfaces"
Yast.import "Host"

module Y2Network
module Wicked
# This class reads the current configuration from `/etc/sysconfig` files
class ConfigReader
class ConfigReader < Y2Network::ConfigReader
include Yast::Logger

def initialize(_opts = {}); end
SECTIONS = [
:interfaces, :connections, :drivers, :routing, :dns, :hostname
].freeze

# @return [Y2Network::Config] Network configuration
def config
# NOTE: This code might be moved outside of the Sysconfig namespace, as it is generic.
# NOTE: /etc/hosts cache - nothing to do with /etc/hostname
Yast::Host.Read

routing_tables = find_routing_tables(interfaces_reader.interfaces)
initial_config = Config.new(source: :wicked)

result = SECTIONS.reduce(initial_config) do |current_config, section|
send("read_#{section}", current_config)
end

log.info "Sysconfig reader result: #{result.inspect}"
result
end

protected

# Reads the network interfaces
#
# @param config [Y2Network::Config] Initial configuration object
# @return [Y2Network::Config] A new configuration object including the interfaces
def read_interfaces(config)
config.update(
interfaces: interfaces_reader.interfaces,
s390_devices: interfaces_reader.s390_devices
)
end

# Reads the connections
#
# @param config [Y2Network::Config] Initial configuration object
# @return [Y2Network::Config] A new configuration object including the connections
def read_connections(config)
connections = connection_configs_reader.connections(config.interfaces)
missing_interfaces = find_missing_interfaces(
connections, config.interfaces
)
config.update(
interfaces: config.interfaces + missing_interfaces,
connections: connections
)
end

# Reads the drivers
#
# @param config [Y2Network::Config] Initial configuration object
# @return [Y2Network::Config] A new configuration object including the connections
def read_drivers(config)
config.update(drivers: interfaces_reader.drivers)
end

# Reads the routing information
#
# @param config [Y2Network::Config] Initial configuration object
# @return [Y2Network::Config] A new configuration object including the routing information
def read_routing(config)
routing_tables = find_routing_tables(config.interfaces)
routing = Routing.new(
tables: routing_tables,
forward_ipv4: sysctl_config_file.forward_ipv4,
forward_ipv6: sysctl_config_file.forward_ipv6
)
config.update(routing: routing)
end

result = Config.new(
interfaces: interfaces_reader.interfaces,
connections: interfaces_reader.connections,
s390_devices: interfaces_reader.s390_devices,
drivers: interfaces_reader.drivers,
routing: routing,
dns: dns,
hostname: hostname,
source: :wicked
)
# Reads the DNS information
#
# @param config [Y2Network::Config] Initial configuration object
# @return [Y2Network::Config] A new configuration object including the DNS configuration
def read_dns(config)
config.update(dns: Y2Network::Wicked::DNSReader.new.config)
end

log.info "Sysconfig reader result: #{result.inspect}"
result
# Returns the Hostname configuration
#
# @param config [Y2Network::Config] Initial configuration object
# @return [Y2Network::Config] A new configuration object including the hostname information
def read_hostname(config)
config.update(hostname: Y2Network::Wicked::HostnameReader.new.config)
end

private

# Returns an interfaces reader instance
#
# @return [SysconfigInterfaces] Interfaces reader
# @return [InterfacesReader] Interfaces reader
def interfaces_reader
@interfaces_reader ||= Y2Network::Wicked::InterfacesReader.new
end

# @return [Y2Network::ConnectionConfigsCollection] Connection configurations collection
def connection_configs_reader
@connection_configs_reader ||= Y2Network::Wicked::ConnectionConfigsReader.new
end

# Adds missing interfaces from connections
#
# @param connections [Y2Network::InterfacesCollection] Known interfaces
# @param interfaces [Y2Network::ConnectionConfigsCollection] Known interfaces
def find_missing_interfaces(connections, interfaces)
empty_collection = Y2Network::InterfacesCollection.new
connections.to_a.each_with_object(empty_collection) do |conn, all|
interface = interfaces.by_name(conn.interface)
next if interface

missing_interface =
if conn.virtual?
VirtualInterface.from_connection(conn)
else
PhysicalInterface.new(conn.name, hardware: Hwinfo.for(conn.name))
end
all << missing_interface
end
end

# Reads routes
#
# Merges routes from /etc/sysconfig/network/routes and /etc/sysconfig/network/ifroute-*
Expand Down Expand Up @@ -123,20 +204,6 @@ def link_routes_to_interfaces(routes, interfaces)
end
end

# Returns the DNS configuration
#
# @return [Y2Network::DNS]
def dns
Y2Network::Wicked::DNSReader.new.config
end

# Returns the Hostname configuration
#
# @return [Y2Network::Hostname]
def hostname
Y2Network::Wicked::HostnameReader.new.config
end

# Returns the Sysctl_Config file class
#
# @return [CFA::SysctlConfig]
Expand Down
51 changes: 51 additions & 0 deletions src/lib/y2network/wicked/connection_configs_reader.rb
@@ -0,0 +1,51 @@
# Copyright (c) [2021] 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 "cfa/interface_file"
require "y2network/connection_configs_collection"
require "y2network/wicked/connection_config_reader"

module Y2Network
module Wicked
# This class reads connection configurations from sysconfig files
#
# @see Y2Network::ConnectionConfigsCollection
class ConnectionConfigsReader
# Returns the connection configurations from sysconfig
#
# It needs the list of known interfaces in order to infer
# the type of the connection.
#
# @param interfaces [Y2Network::InterfacesCollection] Known interfaces
# @return [Y2Network::ConnectionConfigsCollection]
def connections(interfaces)
empty_collection = ConnectionConfigsCollection.new([])
CFA::InterfaceFile.all.each_with_object(empty_collection) do |file, conns|
interface = interfaces.by_name(file.interface)
connection = ConnectionConfigReader.new.read(
file.interface,
interface ? interface.type : nil
)
conns << connection if connection
end
end
end
end
end

0 comments on commit e2e506f

Please sign in to comment.