yast/yast-network

View on GitHub
src/lib/y2network/wicked/config_writer.rb

Summary

Maintainability
A
55 mins
Test Coverage
# 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 "yast"
require "y2network/config"
require "cfa/routes_file"
require "y2network/config_writer"
require "y2network/wicked/connection_config_writer"
require "cfa/sysctl_config"

module Y2Network
  module Wicked
    # This class configures Wicked (through sysconfig) according to a given configuration
    class ConfigWriter < Y2Network::ConfigWriter
    private

      # Updates the ip forwarding config and the routing config which does not
      # belongs to a particular interface
      #
      # @param config     [Y2Network::Config] Current config object
      # @param old_config [Y2Network::Config,nil] Config object with original configuration
      def write_routing(config, old_config, issues_list)
        write_ip_forwarding(config.routing, issues_list)

        # update /etc/sysconfig/network/routes file
        file = routes_file_for(nil)
        file.routes = find_routes_for(nil, config.routing.routes)
        file.save

        write_interface_routes(config, old_config, issues_list)
      end

      # Writes the routes for the configured interfaces removing the ones not
      # configured
      #
      # @param config     [Y2Network::Config] current configuration for writing
      # @param old_config [Y2Network::Config, nil] original configuration used
      #                   for detecting changes. When nil, no actions related to
      #                   configuration changes are processed.
      def write_interface_routes(config, old_config, _issues_list)
        # Write ifroute files
        config.interfaces.each do |dev|
          # S390 devices that have not been activated yet will be part of the
          # collection but with an empty name.
          next if dev.name.empty?

          routes = find_routes_for(dev, config.routing.routes)
          file = routes_file_for(dev)

          # Remove ifroutes-* if empty or interface is not configured
          if routes.empty? || !config.configured_interface?(dev.name)
            file.remove
          else
            file.routes = routes
            file.save
          end
        end

        # Actions needed for removed interfaces
        removed_ifaces = old_config ? old_config.interfaces - config.interfaces : []
        removed_ifaces.each do |iface|
          file = routes_file_for(iface)
          file.remove
        end
        nil
      end

      # Finds routes for a given interface or the routes not tied to any
      # interface in case of nil
      #
      # @param iface  [Interface,nil] Interface to search routes for; nil will
      #   return the routes not tied to any interface
      # @param routes [Array<Route>] List of routes to search in
      # @return [Array<Route>] List of routes for the given interface
      #
      # @see #find_routes_for_iface
      def find_routes_for(iface, routes)
        iface ? find_routes_for_iface(iface, routes) : routes.reject(&:interface)
      end

      # Finds routes for a given interface
      #
      # @param iface  [Interface] Interface to search routes for
      # @param routes [Array<Route>] List of routes to search in
      # @return [Array<Route>] List of routes for the given interface
      def find_routes_for_iface(iface, routes)
        routes.select do |route|
          route.interface == iface
        end
      end

      # Returns the routes file for a given interace
      #
      # @param iface  [Interface,nil] Interface to search routes for; nil will
      #   return the global routes file
      # @return [CFA::RoutesFile]
      def routes_file_for(iface)
        return CFA::RoutesFile.new unless iface

        CFA::RoutesFile.new("/etc/sysconfig/network/ifroute-#{iface.name}")
      end

      # Writes connections configuration
      #
      # @todo Handle old connections (removing those that are not needed, etc.)
      #
      # @param config     [Y2Network::Config] Current config object
      # @param old_config [Y2Network::Config,nil] Config object with original configuration
      def write_connections(config, old_config, _issues_list)
        # FIXME: this code might live in its own class
        writer = Y2Network::Wicked::ConnectionConfigWriter.new
        remove_old_connections(config.connections, old_config.connections, writer) if old_config
        config.connections.each do |conn|
          old_conn = old_config ? old_config.connections.by_ids(conn.id).first : nil
          writer.write(conn, old_conn)
        end
      end

      # Removes old connections files
      #
      # @param conns [ConnectionConfigsCollection] New connections
      # @param old_conns [ConnectionConfigsCollection] Old connections
      # @param writer [Wicked::ConnectionConfigWriter] Writer instance to save changes
      def remove_old_connections(conns, old_conns, writer)
        ids_to_remove = old_conns.map(&:id) - conns.map(&:id)
        to_remove = old_conns.by_ids(*ids_to_remove)
        log.info "removing connections #{to_remove.map(&:name).inspect}"
        to_remove.each { |c| writer.remove(c) }
      end
    end
  end
end