Skip to content

Commit

Permalink
WIP: draft for VolumeOutline (instead of templates)
Browse files Browse the repository at this point in the history
  • Loading branch information
ancorgs committed Jul 17, 2023
1 parent bf8a1c8 commit ed138ce
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 78 deletions.
51 changes: 51 additions & 0 deletions service/lib/agama/storage/btrfs_settings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

# Copyright (c) [2023] 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.

module Agama
module Storage
# Settings regarding Btrfs for a given Volume
class BtrfsSettings
# Whether the volume contains Btrfs snapshots
#
# @return [Boolean]
attr_accessor :snapshots

# @return [Boolean]
attr_accessor :read_only

# @return [Array<String>]
attr_accessor :subvolumes

# @return [String]
attr_accessor :default_subvolume

def initialize
@snapshots = false
@read_only = false
@subvolumes = []
@default_subvolume = "@"
end

def load_features(values)
end
end
end
end
2 changes: 1 addition & 1 deletion service/lib/agama/storage/proposal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def volume_templates
return @volume_templates if @volume_templates

config_volumes = config.data.fetch("storage", {}).fetch("volumes", [])
VolumeTemplate.read(config_volumes)
Volume.read(config_volumes)
end

# Settings with the data used during the calculation of the storage proposal
Expand Down
63 changes: 60 additions & 3 deletions service/lib/agama/storage/volume.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
# find current contact information at www.suse.com.

require "pathname"
require "agama/storage/btrfs_settings"
require "agama/storage/volume_outline"

module Agama
module Storage
Expand All @@ -35,7 +37,10 @@ class Volume
# Used also to match the corresponding volume template
#
# @return [String]
attr_accessor :mount_point
attr_accessor :mount_path

# @return [VolumeOutline]
attr_reader :outline

# Filesystem for the volume
#
Expand All @@ -49,10 +54,10 @@ class Volume
# @return [BtrfsSettings, nil] nil if this does not represent a Btrfs file system
attr_accessor :btrfs

# @return [Array<String]
# @return [Array<String>]
attr_accessor :mount_options

# @return [Array<String]
# @return [Array<String>]
attr_accessor :format_options

# These two would be used to locate the volume in a separate disk
Expand Down Expand Up @@ -80,6 +85,58 @@ class Volume
# @return [Boolean]
attr_accessor :auto_size
alias_method :auto_size?, :auto_size

# Constructor
def initialize(values)
apply_defaults
load_features(values)
end

# Whether the mount point of the volume matches the given one
#
# @param path [String, nil] mount point to check
# @return [Boolean]
def mounted_at?(path)
return false if mount_point.nil? || path.nil?

Pathname.new(mount_point).cleanpath == Pathname.new(path).cleanpath
end

def self.read(volumes_data)
volumes = volumes_data.map { |v| Volume.new(v) }
volumes.each { |v| v.outline.assign_size_relevant_volumes(v, volumes) }
volumes
end

private

def apply_defaults
@mount_options = []
@format_options = []
@btrfs = BtrfsSettings.new
@outline = VolumeOutline.new
end

def load_features(values)
@mount_path = values.fetch("mount", {}).fetch("path")
# @mount_options = xxx
# @format_options = xxx

type_str = values.fetch("filesystem", {}).fetch("type", "ext4")
@fs_type = Y2Storage::Filesystems::Type.find(type.downcase.to_sym)

btrfs.load_features(values)
outline.load_features(values)

# TODO: part of this logic should likely be moved elsewhere (auto_size setter?)
if outline.adaptative_sizes?
@auto_size = true
else
@auto_size = false
@min_size = outline.base_min_size
@max_size = outline.base_max_size
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -23,51 +23,22 @@

module Agama
module Storage
# Starting point to define a Volume. Each product/role will define a set of VolumeTemplates
# to be used as a base to define the storage proposal
class VolumeTemplate
# Mount path
#
# Used to match the volume being defined with the template to use as base.
#
# @return [String]
attr_accessor :mount_point

# Whether the corresponding volume should be in the initial list of volumes created by default
#
# @return [Boolean]
attr_reader :by_default
alias_method :by_default?, :by_default

# Set of rules and features used to fully define and validate a given volume
class VolumeOutline
# Whether the volume is optional
#
# If this is false, the list of volumes used by the storage proposal will always contain a
# volume for this mount_path.
# this volume or an equivalent one (ie. one with the same mount_path).
#
# @return [Boolean]
attr_reader :optional
alias_method :optional?, :optional

# Default filesystem for the volume
#
# @return [Y2Storage::Filesystems::Type]
attr_accessor :fs_type

# Possible filesystem types for the volume
#
# @return [Array<Y2Storage::Filesystems::Type>]
attr_reader :fs_types

# Default values for the btrfs-related options if the volume uses Btrfs
#
# @return [BtrfsSettings, nil] nil if Btrfs is not one of the acceptable fs_types
attr_accessor :btrfs

# Default list of mount options
#
# @return [Array<String]
attr_accessor :mount_options

# Base value to calculate the min size for the volume (if #auto_size is set to true
# for that final volume) or to use as default value (if #auto_size is false)
#
Expand Down Expand Up @@ -112,23 +83,40 @@ class VolumeTemplate
# @return [Integer, nil]
attr_reader :snapshots_percentage

# Constructor
def initialize(template_values)
apply_defaults
load_features(template_values)
def initialize
@optional = false
@fs_types = []
@base_min_size = Y2Storage::DiskSize.zero
@base_max_size = Y2Storage::DiskSize.Unlimited
@size_relevant_volumes = []
@adjust_by_ram = false
@fallback_for_max_size = ""
@fallback_for_min_size = ""
@snapshots_configurable = false
end

def self.read(volumes_data)
templates = volumes_data.map { |v| VolumeTemplate.new(v) }
templates.each { |t| t.assign_size_relevant_volumes(templates) }
templates
def load_features(values)
size = values.fetch("size", {})
min = size["min"]
max = size["max"]
@base_min_size = DiskSize.parse(min, legacy_units: true) if min
@base_max_size = DiskSize.parse(max, legacy_units: true) if max

# @optional
# @fs_types
# @adjust_by_ram
# @fallback_for_max_size
# @fallback_for_min_size
# @snapshots_configurable
# @snapshots_size
# @snapshots_percentage
end

# Sets the mount points that affects the sizes of the volume
def assign_size_relevant_volumes(volumes)
def assign_size_relevant_volumes(volume, other_volumes)
# FIXME: this should be a responsibility of the Proposal (since it's calculated by
# Proposal::DevicesPlanner)
@size_relevant_volumes = specs.select { |s| fallback?(s) }.map(&:mount_point)
@size_relevant_volumes = other_volumes.select { |v| fallback?(volume, v) }.map(&:mount_path)
end

# Whether it makes sense to have automatic size limits for the volume
Expand All @@ -153,42 +141,16 @@ def snapshots_affect_sizes?
snapshots_percentage && !snapshots_percentage.zero?
end

# Whether the mount point of the volume matches the given one
#
# @param path [String, nil] mount point to check
# @return [Boolean]
def mounted_at?(path)
return false if mount_point.nil? || path.nil?

Pathname.new(mount_point).cleanpath == Pathname.new(path).cleanpath
end

private

def apply_defaults
@by_default = true
@optional = true
@btrfs = BtrfsSettings.new
@snapshots_configurable = false
@mount_options = []
@fs_types = []
@base_min_size = Y2Storage::DiskSize.zero
@base_max_size = Y2Storage::DiskSize.Unlimited
@adjust_by_ram = false
@fallback_for_min_size = nil
@fallback_for_max_size = nil
@size_relevant_volumes = []
end

def load_features(values)
end

# Whether the given volume template has this volume as fallback for sizes
# Whether the given volume outline has this volume as fallback for sizes
#
# @param other [VolumeTemplate]
# @param volume [Volume] the volume of this outline
# @param other [Volume]
# @return [Boolean]
def fallback?(other)
mounted_at?(spec.fallback_for_min_size) || mounted_at?(other.fallback_for_max_size)
def fallback?(volume, other)
volume.mounted_at?(other.outline.fallback_for_min_size) ||
volume.mounted_at?(other.outline.fallback_for_max_size)
end
end
end
Expand Down

0 comments on commit ed138ce

Please sign in to comment.