Class: Pvectl::Services::EditContainer
- Inherits:
-
Object
- Object
- Pvectl::Services::EditContainer
- Defined in:
- lib/pvectl/services/edit_container.rb,
sig/pvectl/services/edit_container.rbs
Overview
Orchestrates the interactive container configuration editing flow.
Fetches current config, opens it in an editor as structured YAML, validates changes, computes a diff, and applies updates via the API. Supports dry-run mode and optimistic locking via digest.
Instance Method Summary collapse
-
#build_result(resource_info, **attrs) ⇒ Models::ContainerOperationResult
Builds a ContainerOperationResult with the :edit operation.
-
#build_update_params(changes, original_config) ⇒ Hash
Builds API update parameters from a diff hash.
-
#execute(ctid:) ⇒ Models::ContainerOperationResult?
Executes the interactive container edit flow.
-
#initialize(container_repository:, editor_session: nil, options: {}) ⇒ EditContainer
constructor
Creates a new EditContainer service.
-
#not_found_result(ctid) ⇒ Models::ContainerOperationResult
Builds a not-found error result.
Constructor Details
#initialize(container_repository:, editor_session: nil, options: {}) ⇒ EditContainer
Creates a new EditContainer service.
26 27 28 29 30 |
# File 'lib/pvectl/services/edit_container.rb', line 26 def initialize(container_repository:, editor_session: nil, options: {}) @container_repository = container_repository @editor_session = editor_session @options = end |
Instance Method Details
#build_result(resource_info, **attrs) ⇒ Models::ContainerOperationResult
Builds a ContainerOperationResult with the :edit operation.
106 107 108 109 110 111 112 113 114 |
# File 'lib/pvectl/services/edit_container.rb', line 106 def build_result(resource_info, **attrs) container = Models::Container.new( vmid: resource_info[:ctid], node: resource_info[:node] ) Models::ContainerOperationResult.new( operation: :edit, container: container, resource: resource_info, **attrs ) end |
#build_update_params(changes, original_config) ⇒ Hash
Builds API update parameters from a diff hash.
Maps changed/added keys to their new values, removed keys to the
Proxmox delete parameter, and includes digest for optimistic locking.
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/pvectl/services/edit_container.rb', line 90 def build_update_params(changes, original_config) params = {} changes[:changed].each { |key, (_old, new_val)| params[key] = new_val } changes[:added].each { |key, val| params[key] = val } unless changes[:removed].empty? params[:delete] = changes[:removed].map(&:to_s).join(",") end params[:digest] = original_config[:digest] if original_config[:digest] params end |
#execute(ctid:) ⇒ Models::ContainerOperationResult?
Executes the interactive container edit flow.
36 37 38 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 73 74 75 76 77 78 |
# File 'lib/pvectl/services/edit_container.rb', line 36 def execute(ctid:) container = @container_repository.get(ctid) return not_found_result(ctid) unless container config = @container_repository.fetch_config(container.node, ctid) resource_info = { ctid: ctid, node: container.node, status: container.status } yaml_content = ConfigSerializer.to_yaml(config, type: :container, resource: resource_info) validator = ->(content) { ConfigSerializer.validate(content, type: :container) } session = @editor_session || EditorSession.new(validator: validator) edited = session.edit(yaml_content) return nil unless edited original_roundtrip = ConfigSerializer.from_yaml(yaml_content, type: :container) edited_flat = ConfigSerializer.from_yaml(edited, type: :container) violations = ConfigSerializer.readonly_violations(original_roundtrip, edited_flat, type: :container) unless violations.empty? return build_result(resource_info, success: false, error: "Read-only fields cannot be changed: #{violations.join(', ')}") end changes = ConfigSerializer.diff(original_roundtrip, edited_flat) if changes[:changed].empty? && changes[:added].empty? && changes[:removed].empty? return nil end params = build_update_params(changes, config) resource_info[:diff] = changes if @options[:dry_run] return build_result(resource_info, success: true) end @container_repository.update(ctid, container.node, params) build_result(resource_info, success: true) rescue StandardError => e build_result({ ctid: ctid }, success: false, error: e.) end |
#not_found_result(ctid) ⇒ Models::ContainerOperationResult
Builds a not-found error result.
120 121 122 |
# File 'lib/pvectl/services/edit_container.rb', line 120 def not_found_result(ctid) build_result({ ctid: ctid }, success: false, error: "Container #{ctid} not found") end |