Class: Pvectl::Services::EditVolume
- Inherits:
-
Object
- Object
- Pvectl::Services::EditVolume
- Defined in:
- lib/pvectl/services/edit_volume.rb,
sig/pvectl/services/edit_volume.rbs
Overview
Orchestrates the interactive volume property editing flow.
Fetches the disk config string from VM/CT config, parses it into editable YAML (key-value pairs), opens editor, and applies changes. Size changes delegate to ResizeVolume; config changes rebuild the disk config string.
Instance Method Summary collapse
-
#apply_changes(id, disk, node, original_disk_value, changes) ⇒ void
Applies changes — delegates size to ResizeVolume, config to rebuild.
-
#build_result(id, disk, node, **attrs) ⇒ Models::VolumeOperationResult
Builds a VolumeOperationResult.
-
#build_yaml_content(editable, disk, id, node) ⇒ String
Builds YAML content for the editor with comment header.
-
#compute_diff(original, edited) ⇒ Hash
Computes diff between original and edited config.
-
#execute(id:, disk:, node:) ⇒ Models::VolumeOperationResult?
Executes the interactive volume edit flow.
-
#initialize(repository:, resource_type:, editor_session: nil, options: {}) ⇒ EditVolume
constructor
A new instance of EditVolume.
-
#no_changes?(changes) ⇒ Boolean
Checks whether the diff contains any actual changes.
-
#parse_disk_config(disk_value) ⇒ Hash
Parses a disk config string into a hash of editable properties.
-
#parse_edited_yaml(edited) ⇒ Hash
Parses edited YAML content, stripping comment lines.
-
#rebuild_disk_config(current_value, updates, removed_keys = []) ⇒ String
Rebuilds a disk config string with updated/removed properties.
Constructor Details
#initialize(repository:, resource_type:, editor_session: nil, options: {}) ⇒ EditVolume
Returns a new instance of EditVolume.
26 27 28 29 30 31 |
# File 'lib/pvectl/services/edit_volume.rb', line 26 def initialize(repository:, resource_type:, editor_session: nil, options: {}) @repository = repository @resource_type = resource_type @editor_session = editor_session @options = end |
Instance Method Details
#apply_changes(id, disk, node, original_disk_value, changes) ⇒ void
This method returns an undefined value.
Applies changes — delegates size to ResizeVolume, config to rebuild.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/pvectl/services/edit_volume.rb', line 160 def apply_changes(id, disk, node, original_disk_value, changes) size_change = changes[:changed].delete("size") || changes[:added].delete("size") if size_change new_size = size_change.is_a?(Array) ? size_change[1] : size_change parsed_size = ResizeVolume.parse_size(new_size.to_s) resize_service = ResizeVolume.new(repository: @repository) resize_service.preflight(id, disk, parsed_size, node: node) resize_service.perform(id, disk, parsed_size.raw, node: node) end config_updates = {} changes[:changed].each { |key, (_old, new_val)| config_updates[key] = new_val } changes[:added].each { |key, val| config_updates[key] = val } if !config_updates.empty? || !changes[:removed].empty? new_disk_value = rebuild_disk_config(original_disk_value, config_updates, changes[:removed]) @repository.update(id, node, { disk.to_sym => new_disk_value }) end end |
#build_result(id, disk, node, **attrs) ⇒ Models::VolumeOperationResult
Builds a VolumeOperationResult.
211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/pvectl/services/edit_volume.rb', line 211 def build_result(id, disk, node, **attrs) volume = Models::Volume.new( name: disk, resource_type: @resource_type.to_s, resource_id: id, node: node ) Models::VolumeOperationResult.new( operation: :edit, volume: volume, **attrs ) end |
#build_yaml_content(editable, disk, id, node) ⇒ String
Builds YAML content for the editor with comment header.
104 105 106 107 108 |
# File 'lib/pvectl/services/edit_volume.rb', line 104 def build_yaml_content(editable, disk, id, node) "# Volume: #{disk} (resource #{id} on #{node})\n" \ "# Edit properties below. Save and close to apply.\n" + editable.to_yaml end |
#compute_diff(original, edited) ⇒ Hash
Computes diff between original and edited config.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/pvectl/services/edit_volume.rb', line 132 def compute_diff(original, edited) changed = {} added = {} removed = [] edited.each do |key, value| orig_value = original[key.to_s] if orig_value.nil? added[key.to_s] = value elsif orig_value.to_s != value.to_s changed[key.to_s] = [orig_value.to_s, value.to_s] end end original.each_key do |key| removed << key.to_s unless edited.key?(key.to_s) end { changed: changed, added: added, removed: removed } end |
#execute(id:, disk:, node:) ⇒ Models::VolumeOperationResult?
Executes the interactive volume edit flow.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/pvectl/services/edit_volume.rb', line 39 def execute(id:, disk:, node:) config = @repository.fetch_config(node, id) disk_value = config[disk.to_sym] unless disk_value return build_result(id, disk, node, success: false, error: "Volume '#{disk}' not found in config for resource #{id}") end editable = parse_disk_config(disk_value) yaml_content = build_yaml_content(editable, disk, id, node) session = @editor_session || EditorSession.new edited = session.edit(yaml_content) return nil unless edited edited_config = parse_edited_yaml(edited) changes = compute_diff(editable, edited_config) return nil if no_changes?(changes) if @options[:dry_run] return build_result(id, disk, node, success: true, resource: { diff: changes }) end apply_changes(id, disk, node, disk_value, changes) build_result(id, disk, node, success: true) rescue ResizeVolume::VolumeNotFoundError, ResizeVolume::SizeTooSmallError, ArgumentError => e build_result(id, disk, node, success: false, error: e.) rescue StandardError => e build_result(id, disk, node, success: false, error: e.) end |
#no_changes?(changes) ⇒ Boolean
Checks whether the diff contains any actual changes.
123 124 125 |
# File 'lib/pvectl/services/edit_volume.rb', line 123 def no_changes?(changes) changes[:changed].empty? && changes[:added].empty? && changes[:removed].empty? end |
#parse_disk_config(disk_value) ⇒ Hash
Parses a disk config string into a hash of editable properties.
Input: "local-lvm:vm-100-disk-0,size=32G,cache=none" Output: { "size" => "32G", "cache" => "none" }
The base (storage:vol-id) is NOT included — it's read-only.
85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/pvectl/services/edit_volume.rb', line 85 def parse_disk_config(disk_value) parts = disk_value.to_s.split(",") parts.shift # Remove base "storage:vol-id" props = {} parts.each do |part| key, value = part.split("=", 2) props[key] = value end props end |
#parse_edited_yaml(edited) ⇒ Hash
Parses edited YAML content, stripping comment lines.
114 115 116 117 |
# File 'lib/pvectl/services/edit_volume.rb', line 114 def parse_edited_yaml(edited) cleaned = edited.lines.reject { |l| l.strip.start_with?("#") }.join YAML.safe_load(cleaned) || {} end |
#rebuild_disk_config(current_value, updates, removed_keys = []) ⇒ String
Rebuilds a disk config string with updated/removed properties.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/pvectl/services/edit_volume.rb', line 187 def rebuild_disk_config(current_value, updates, removed_keys = []) parts = current_value.to_s.split(",") base = parts.shift existing = {} parts.each do |part| key, value = part.split("=", 2) existing[key] = value end updates.each { |key, value| existing[key.to_s] = value.to_s } removed_keys.each { |key| existing.delete(key.to_s) } config_parts = existing.map { |k, v| "#{k}=#{v}" } ([base] + config_parts).join(",") end |