src/lib/y2storage/proposal/settings_generator.rb
# Copyright (c) [2018-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 "y2storage/proposal/settings_adjustment"
module Y2Storage
module Proposal
# Class for a settings generator used to perform the initial proposal
#
# @see InitialGuidedProposal
class SettingsGenerator
include Yast::Logger
# Constructor
#
# A copy of the given settings is internally stored.
#
# @param settings [ProposalSettings] base settings
def initialize(settings)
@settings = settings.deep_copy
@adjustments = SettingsAdjustment.new
end
# This attribute contains information about any adjustment done to the settings
#
# @return [Proposal::SettingsAdjustment]
attr_reader :adjustments
# Next settings generated from the current version of the settings. The new settings are
# generated by disabling some of its properties. A copy of the stored {#settings} is returned.
#
# @see #calculate_next_settings
#
# @return [ProposalSettings, nil] nil if nothing else can be disabled in the current settings
def next_settings
initial_settings || calculate_next_settings
end
private
# Next settings to use for a new attempt of the {InitialGuidedProposal}
#
# It tries to disable any property from the first configurable volume: adjust by ram,
# snapshots or the volume itself.
#
# @see #next_settings
#
# @return [ProposalSettings, nil] nil if nothing else can be disabled in the current settings
def calculate_next_settings
volume = first_configurable_volume
return nil if volume.nil?
settings_after_disabling_adjust_by_ram(volume) ||
settings_after_disabling_snapshots(volume) ||
settings_after_disabling_volume(volume)
end
# Current settings
#
# This settings are used to calculate the next settings
#
# @return [ProposalSettings]
attr_reader :settings
# Settings to use for first time
#
# The first time that {#next_settings} is called, a copy of the original settings
# is returned.
#
# @return [ProposalSettings]
def initial_settings
return nil if @used_initial_settings
@used_initial_settings = true
copy_settings
end
# Copies current settings
#
# @return [ProposalSettings]
def copy_settings
settings.deep_copy
end
# Returns the first volume (according to disable_order) whose settings could be modified.
#
# @note Volumes without disable order are never altered.
#
# @return [VolumeSpecification, nil]
def first_configurable_volume
settings.volumes.select { |v| configurable_volume?(v) }.min_by(&:disable_order)
end
# Copy of the current settings after disabling adjust by ram property from the
# given volume specification.
#
# @param volume [VolumeSpecification]
# @return [ProposalSettings, nil] nil if adjust by ram is already disabled
def settings_after_disabling_adjust_by_ram(volume)
return nil unless adjust_by_ram_active_and_configurable?(volume)
disable_volume_property(volume, :adjust_by_ram)
copy_settings
end
# Copy of the current settings after disabling snapshots property from the
# given volume specification.
#
# @param volume [VolumeSpecification]
# @return [ProposalSettings, nil] nil if snapshots is already disabled
def settings_after_disabling_snapshots(volume)
return nil unless snapshots_active_and_configurable?(volume)
disable_volume_property(volume, :snapshots)
copy_settings
end
# Copy of the current settings after disabling the given volume specification
#
# @param volume [VolumeSpecification]
# @return [ProposalSettings, nil] nil if the volume is already disabled
def settings_after_disabling_volume(volume)
return nil unless proposed_active_and_configurable?(volume)
disable_volume_property(volume, :proposed)
copy_settings
end
def disable_volume_property(volume, property)
log.info("Disabling '#{property}' for '#{volume.mount_point}'")
volume.public_send(:"#{property}=", false)
@adjustments = adjustments.add_volume_attr(volume, property, false)
end
# A volume is configurable if it is proposed and its settings can be modified.
# That is, #adjust_by_ram, #snapshots or #proposed are true and some of them
# could be change to false.
#
# @note A volume is considered configurable if it has disable order. Otherwise,
# only the user is allowed to manually disable the volume or any of its features
# (e.g. snapshots) using the UI.
#
# @param volume [VolumeSpecification]
# @return [Boolean]
def configurable_volume?(volume)
volume.proposed? && !volume.disable_order.nil? && (
proposed_active_and_configurable?(volume) ||
adjust_by_ram_active_and_configurable?(volume) ||
snapshots_active_and_configurable?(volume))
end
# Whether the volume is proposed and it could be configured
#
# @param volume [VolumeSpecification]
# @return [Boolean]
def proposed_active_and_configurable?(volume)
active_and_configurable?(volume, :proposed)
end
# Whether the volume has adjust_by_ram to true and it could be configured
#
# @param volume [VolumeSpecification]
# @return [Boolean]
def adjust_by_ram_active_and_configurable?(volume)
active_and_configurable?(volume, :adjust_by_ram)
end
# Whether the volume has snapshots to true and it could be configured
#
# @param volume [VolumeSpecification]
# @return [Boolean]
def snapshots_active_and_configurable?(volume)
return false unless volume.fs_type.is?(:btrfs)
active_and_configurable?(volume, :snapshots)
end
# Whether a volume has an attribute to true and it could be configured
#
# @param volume [VolumeSpecification]
# @param attr [String, Symbol]
#
# @return [Boolean]
def active_and_configurable?(volume, attr)
volume.send(attr) && volume.send("#{attr}_configurable")
end
end
end
end