Class: Pvectl::Services::EditNode
- Inherits:
-
Object
- Object
- Pvectl::Services::EditNode
- Defined in:
- lib/pvectl/services/edit_node.rb,
sig/pvectl/services/edit_node.rbs
Overview
Orchestrates the interactive node configuration editing flow.
Fetches current config, presents it as YAML in an editor, computes diff, and applies changes. Uses plain YAML (not ConfigSerializer) since node config is flat key-value.
Constant Summary collapse
- READONLY_KEYS =
Read-only keys that should not be sent back to the API.
i[digest].freeze
Instance Method Summary collapse
-
#build_result(resource_info, **attrs) ⇒ Models::NodeOperationResult
Builds a NodeOperationResult with the :edit operation.
-
#build_update_params(changes, original_config) ⇒ Hash
Builds API update parameters from diff.
-
#compute_diff(original, edited) ⇒ Hash
Computes diff between original and edited config.
-
#execute(node_name:) ⇒ Models::NodeOperationResult?
Executes the interactive node edit flow.
-
#initialize(node_repository:, editor_session: nil, options: {}) ⇒ EditNode
constructor
Creates a new EditNode service.
-
#not_found_result(node_name) ⇒ Models::NodeOperationResult
Builds a not-found error result.
Constructor Details
#initialize(node_repository:, editor_session: nil, options: {}) ⇒ EditNode
Creates a new EditNode service.
29 30 31 32 33 |
# File 'lib/pvectl/services/edit_node.rb', line 29 def initialize(node_repository:, editor_session: nil, options: {}) @node_repository = node_repository @editor_session = editor_session = end |
Instance Method Details
#build_result(resource_info, **attrs) ⇒ Models::NodeOperationResult
Builds a NodeOperationResult with the :edit operation.
131 132 133 134 135 136 |
# File 'lib/pvectl/services/edit_node.rb', line 131 def build_result(resource_info, **attrs) node_model = Models::Node.new(name: resource_info[:node_name]) Models::NodeOperationResult.new( operation: :edit, node_model: node_model, resource: resource_info, **attrs ) end |
#build_update_params(changes, original_config) ⇒ Hash
Builds API update parameters from diff.
115 116 117 118 119 120 121 122 123 124 |
# File 'lib/pvectl/services/edit_node.rb', line 115 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 |
#compute_diff(original, edited) ⇒ Hash
Computes diff between original and edited config.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/pvectl/services/edit_node.rb', line 89 def compute_diff(original, edited) changed = {} added = {} removed = [] edited.each do |key, value| orig_value = original[key] if orig_value.nil? added[key] = value elsif orig_value.to_s != value.to_s changed[key] = [orig_value.to_s, value.to_s] end end original.each_key do |key| removed << key unless edited.key?(key) end { changed: changed, added: added, removed: removed } end |
#execute(node_name:) ⇒ Models::NodeOperationResult?
Executes the interactive node 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 73 74 75 76 77 78 79 80 |
# File 'lib/pvectl/services/edit_node.rb', line 39 def execute(node_name:) node = @node_repository.get(node_name) return not_found_result(node_name) unless node config = @node_repository.fetch_config(node_name) resource_info = { node_name: node_name, status: node.status } # Build editable YAML (exclude digest — it's for optimistic locking only) editable = config.reject { |k, _| READONLY_KEYS.include?(k) } # Convert symbol keys to strings for clean YAML output (avoids :key: format) string_keyed = editable.transform_keys(&:to_s) yaml_content = "# Node: #{node_name}\n# Edit configuration below. Save and close to apply.\n" + string_keyed.to_yaml session = @editor_session || EditorSession.new edited = session.edit(yaml_content) return nil unless edited # Parse edited YAML (strip comment lines) cleaned = edited.lines.reject { |l| l.strip.start_with?("#") }.join edited_config = YAML.safe_load(cleaned, symbolize_names: true) || {} # Compute diff against original editable config (with symbol keys) changes = compute_diff(editable, edited_config) if changes[:changed].empty? && changes[:added].empty? && changes[:removed].empty? return nil end resource_info[:diff] = changes if [:dry_run] return build_result(resource_info, success: true) end update_params = build_update_params(changes, config) @node_repository.update(node_name, update_params) build_result(resource_info, success: true) rescue StandardError => e build_result({ node_name: node_name }, success: false, error: e.) end |
#not_found_result(node_name) ⇒ Models::NodeOperationResult
Builds a not-found error result.
142 143 144 |
# File 'lib/pvectl/services/edit_node.rb', line 142 def not_found_result(node_name) build_result({ node_name: node_name }, success: false, error: "Node #{node_name} not found") end |