Module: Pvectl::Commands::FeatureCommand
- Included in:
- FeatureContainer, FeatureVm
- Defined in:
- lib/pvectl/commands/feature_command.rb,
sig/pvectl/commands/feature_command.rbs
Overview
Shared functionality for the feature query commands (feature vm, feature ct).
Queries whether a Proxmox feature (clone, snapshot, copy) is available for a given VM or container. Availability depends on storage type, snapshot state, and other server-side conditions.
Designed with the hybrid Template Method pattern (MoveDiskCommand /
MigrateCommand) — specializations only set RESOURCE_TYPE and
SUPPORTED_RESOURCES; the FeatureVm specialization additionally implements
.register which wires the GLI command.
Defined Under Namespace
Modules: ClassMethods
Constant Summary collapse
- VALID_FEATURES =
Valid feature names per Proxmox API (both QEMU and LXC endpoints).
%w[clone snapshot copy].freeze
Class Method Summary collapse
-
.included(base) ⇒ void
Hook called when the module is included.
Instance Method Summary collapse
-
#build_repository(connection) ⇒ Repositories::Vm, Repositories::Container
Builds the resource repository (VM or Container) for the current type.
-
#execute ⇒ Integer
Executes the feature query.
-
#id_label ⇒ String
Returns the human label for the resource ID ("VMID" or "CTID").
-
#initialize(args, options, global_options) ⇒ FeatureCommand
Initializes a feature query command.
-
#load_config ⇒ void
Loads configuration from file or environment.
-
#output_result(result, feature) ⇒ void
Outputs the result in the requested format.
-
#payload(result, feature) ⇒ Hash
Builds the structured result payload for JSON/YAML output.
-
#perform_operation(id, feature) ⇒ Integer
Performs the feature availability check.
-
#resolve_resource(connection, id) ⇒ Models::Vm, ...
Resolves the resource (VM or container) by ID using the appropriate repository.
-
#resource_not_found(id) ⇒ Integer
Outputs "not found" error and returns the not-found exit code.
-
#resource_type_symbol ⇒ Symbol
Returns the resource type symbol (:vm or :container).
-
#stringify_keys(hash) ⇒ Hash
Converts symbol keys to strings for YAML output.
-
#type_name ⇒ String
Returns the singular type name ("VM" or "container") used in error messages.
-
#usage_error(message) ⇒ Integer
Outputs usage error and returns the usage exit code.
Class Method Details
.included(base) ⇒ void
This method returns an undefined value.
Hook called when the module is included.
43 44 45 |
# File 'lib/pvectl/commands/feature_command.rb', line 43 def self.included(base) base.extend(ClassMethods) end |
Instance Method Details
#build_repository(connection) ⇒ Repositories::Vm, Repositories::Container
Builds the resource repository (VM or Container) for the current type.
145 146 147 148 149 150 151 |
# File 'lib/pvectl/commands/feature_command.rb', line 145 def build_repository(connection) if resource_type_symbol == :vm Pvectl::Repositories::Vm.new(connection) else Pvectl::Repositories::Container.new(connection) end end |
#execute ⇒ Integer
Executes the feature query.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/pvectl/commands/feature_command.rb', line 61 def execute return usage_error("#{id_label} is required") if @args.empty? return usage_error("FEATURE is required") if @args.size < 2 id_str = @args[0] feature = @args[1] unless id_str.to_s.match?(/\A\d+\z/) return usage_error("Invalid #{id_label}: #{id_str}") end unless VALID_FEATURES.include?(feature) return usage_error( "Invalid feature: #{feature} (allowed: #{VALID_FEATURES.join(', ')})" ) end perform_operation(id_str.to_i, feature) end |
#id_label ⇒ String
Returns the human label for the resource ID ("VMID" or "CTID").
93 94 95 |
# File 'lib/pvectl/commands/feature_command.rb', line 93 def id_label resource_type_symbol == :vm ? "VMID" : "CTID" end |
#initialize(args, options, global_options) ⇒ FeatureCommand
Initializes a feature query command.
52 53 54 55 56 |
# File 'lib/pvectl/commands/feature_command.rb', line 52 def initialize(args, , ) @args = Array(args).compact = = end |
#load_config ⇒ void
This method returns an undefined value.
Loads configuration from file or environment.
156 157 158 159 160 |
# File 'lib/pvectl/commands/feature_command.rb', line 156 def load_config service = Pvectl::Config::Service.new service.load(config: [:config]) @config = service.current_config end |
#output_result(result, feature) ⇒ void
This method returns an undefined value.
Outputs the result in the requested format.
Plain output: "available"/"unavailable" + optional list of capable nodes. JSON/YAML output: structured hash with feature metadata.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/pvectl/commands/feature_command.rb', line 170 def output_result(result, feature) format = ([:output] || "plain").to_s case format when "json" require "json" $stdout.puts JSON.pretty_generate(payload(result, feature)) when "yaml" require "yaml" $stdout.puts YAML.dump(stringify_keys(payload(result, feature))) else status = result[:available] ? "available" : "unavailable" $stdout.puts status if result[:available] && !result[:nodes].empty? $stdout.puts "nodes: #{result[:nodes].join(', ')}" end end end |
#payload(result, feature) ⇒ Hash
Builds the structured result payload for JSON/YAML output.
194 195 196 197 198 199 200 201 |
# File 'lib/pvectl/commands/feature_command.rb', line 194 def payload(result, feature) { available: result[:available], feature: feature, snapname: [:snapname], nodes: result[:nodes] } end |
#perform_operation(id, feature) ⇒ Integer
Performs the feature availability check.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/pvectl/commands/feature_command.rb', line 109 def perform_operation(id, feature) load_config connection = Pvectl::Connection.new(@config) resource = resolve_resource(connection, id) return resource_not_found(id) if resource.nil? result = build_repository(connection) .feature_available?(id, resource.node, feature, snapname: [:snapname]) output_result(result, feature) result[:available] ? ExitCodes::SUCCESS : ExitCodes::GENERAL_ERROR rescue Pvectl::Config::ConfigNotFoundError, Pvectl::Config::InvalidConfigError, Pvectl::Config::ContextNotFoundError, Pvectl::Config::ClusterNotFoundError, Pvectl::Config::UserNotFoundError raise rescue StandardError => e $stderr.puts "Error: #{e.message}" ExitCodes::GENERAL_ERROR end |
#resolve_resource(connection, id) ⇒ Models::Vm, ...
Resolves the resource (VM or container) by ID using the appropriate repository.
137 138 139 |
# File 'lib/pvectl/commands/feature_command.rb', line 137 def resolve_resource(connection, id) build_repository(connection).get(id) end |
#resource_not_found(id) ⇒ Integer
Outputs "not found" error and returns the not-found exit code.
224 225 226 227 |
# File 'lib/pvectl/commands/feature_command.rb', line 224 def resource_not_found(id) $stderr.puts "Error: No #{type_name} found with ID #{id}" ExitCodes::NOT_FOUND end |
#resource_type_symbol ⇒ Symbol
Returns the resource type symbol (:vm or :container).
86 87 88 |
# File 'lib/pvectl/commands/feature_command.rb', line 86 def resource_type_symbol self.class::RESOURCE_TYPE end |
#stringify_keys(hash) ⇒ Hash
Converts symbol keys to strings for YAML output.
207 208 209 |
# File 'lib/pvectl/commands/feature_command.rb', line 207 def stringify_keys(hash) hash.each_with_object({}) { |(k, v), acc| acc[k.to_s] = v } end |
#type_name ⇒ String
Returns the singular type name ("VM" or "container") used in error messages.
100 101 102 |
# File 'lib/pvectl/commands/feature_command.rb', line 100 def type_name resource_type_symbol == :vm ? "VM" : "container" end |
#usage_error(message) ⇒ Integer
Outputs usage error and returns the usage exit code.
215 216 217 218 |
# File 'lib/pvectl/commands/feature_command.rb', line 215 def usage_error() $stderr.puts "Error: #{message}" ExitCodes::USAGE_ERROR end |