Class: Pvectl::Commands::SetVolume

Inherits:
Object
  • Object
show all
Extended by:
ClassMethods
Defined in:
lib/pvectl/commands/set_volume.rb,
sig/pvectl/commands/set_volume.rbs

Overview

Handler for the pvectl set volume command.

Does NOT use SetResourceCommand template — has custom flow due to different argument structure (resource_type + id + disk + key=value).

Examples:

Resize volume

pvectl set volume vm 100 scsi0 size=+10G

Set cache mode

pvectl set volume vm 100 scsi0 cache=writeback

Mixed operations

pvectl set volume vm 100 scsi0 size=+10G cache=writeback --yes

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Constructor Details

#initialize(args, options, global_options) ⇒ SetVolume

Initializes a set volume command.

Parameters:

  • args (Array<String>)

    command arguments

  • options (Hash)

    command options

  • global_options (Hash)

    global CLI options



40
41
42
43
44
# File 'lib/pvectl/commands/set_volume.rb', line 40

def initialize(args, options, global_options)
  @args = args
  @options = options
  @global_options = global_options
end

Instance Method Details

#build_repository(connection, resource_type) ⇒ Repositories::Vm, Repositories::Container

Builds repository for resource type.

Parameters:

  • connection (Connection)

    API connection

  • resource_type (String)

    resource type

Returns:



156
157
158
159
160
161
162
163
164
165
# File 'lib/pvectl/commands/set_volume.rb', line 156

def build_repository(connection, resource_type)
  case resource_type
  when "vm"
    Pvectl::Repositories::Vm.new(connection)
  when "container", "ct"
    Pvectl::Repositories::Container.new(connection)
  else
    raise ArgumentError, "Unknown resource type: #{resource_type}"
  end
end

#confirm_resize(resource_id, disk, size) ⇒ Boolean

Confirms resize operation.

Parameters:

  • resource_id (String)

    resource ID

  • disk (String)

    disk name

  • size (String)

    size value

Returns:

  • (Boolean)

    true if should proceed



140
141
142
143
144
145
146
147
148
149
# File 'lib/pvectl/commands/set_volume.rb', line 140

def confirm_resize(resource_id, disk, size)
  $stdout.puts "Resize volume #{disk} on resource #{resource_id}:"
  $stdout.puts "  New size: #{size}"
  $stdout.puts ""
  $stdout.puts "This action is IRREVERSIBLE — volumes cannot be shrunk via API."
  $stdout.print "Proceed? [y/N]: "

  response = $stdin.gets&.strip&.downcase
  %w[y yes].include?(response)
end

#executeInteger

Executes the set volume command.

Returns:

  • (Integer)

    exit code



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
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/pvectl/commands/set_volume.rb', line 49

def execute
  resource_type = @args[0]
  resource_id = @args[1]
  disk = @args[2]
  key_value_args = @args[3..] || []

  return usage_error("Resource type required (vm, container)") unless resource_type
  return usage_error("Resource ID is required") unless resource_id
  return usage_error("Volume name is required (e.g., scsi0, rootfs)") unless disk

  key_values = parse_key_values(key_value_args)
  return usage_error("At least one key=value pair is required") if key_values.empty?

  load_config
  connection = Pvectl::Connection.new(@config)

  node = resolve_node(resource_id.to_i, connection, resource_type)
  return ExitCodes::NOT_FOUND unless node

  # Confirmation for resize operations
  if key_values.key?("size") && !@options[:yes]
    return ExitCodes::SUCCESS unless confirm_resize(resource_id, disk, key_values["size"])
  end

  repo = build_repository(connection, resource_type)
  service = Pvectl::Services::SetVolume.new(
    repository: repo,
    resource_type: resource_type_symbol(resource_type)
  )
  result = service.execute(id: resource_id.to_i, disk: disk, params: key_values, node: node)

  output_result(result)

  result.successful? ? 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

#load_configvoid

This method returns an undefined value.

Loads configuration.



196
197
198
199
200
# File 'lib/pvectl/commands/set_volume.rb', line 196

def load_config
  service = Pvectl::Config::Service.new
  service.load(config: @global_options[:config])
  @config = service.current_config
end

#output_result(result) ⇒ void

This method returns an undefined value.

Outputs operation result.

Parameters:



183
184
185
186
187
188
189
190
191
# File 'lib/pvectl/commands/set_volume.rb', line 183

def output_result(result)
  presenter = Pvectl::Presenters::VolumeOperationResult.new
  format = @global_options[:output] || "table"
  color_flag = @global_options[:color]

  formatter = Pvectl::Formatters::Registry.for(format)
  output = formatter.format([result], presenter, color: color_flag)
  puts output
end

#parse_key_values(args) ⇒ Hash

Parses key=value pairs from argument list.

Parameters:

  • args (Array<String>)

    arguments

Returns:

  • (Hash)

    parsed pairs



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/pvectl/commands/set_volume.rb', line 100

def parse_key_values(args)
  pairs = {}
  args.each do |arg|
    unless arg.include?("=")
      $stderr.puts "Warning: Ignoring argument without '=': #{arg}"
      next
    end
    key, value = arg.split("=", 2)
    pairs[key] = value
  end
  pairs
end

#resolve_node(resource_id, connection, resource_type) ⇒ String?

Resolves node for a resource.

Parameters:

  • resource_id (Integer)

    resource ID

  • connection (Connection)

    API connection

  • resource_type (String)

    resource type

Returns:

  • (String, nil)

    node name or nil



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/pvectl/commands/set_volume.rb', line 119

def resolve_node(resource_id, connection, resource_type)
  return @options[:node] if @options[:node]

  resolver = Pvectl::Utils::ResourceResolver.new(connection)
  resolved = resolver.resolve(resource_id)

  unless resolved
    label = resource_type == "vm" ? "VM" : "container"
    $stderr.puts "Error: #{label} #{resource_id} not found"
    return nil
  end

  resolved[:node]
end

#resource_type_symbol(resource_type) ⇒ Symbol

Converts string resource type to symbol.

Parameters:

  • resource_type (String)

    resource type

Returns:

  • (Symbol)

    :vm or :container



171
172
173
174
175
176
177
# File 'lib/pvectl/commands/set_volume.rb', line 171

def resource_type_symbol(resource_type)
  case resource_type
  when "vm" then :vm
  when "container", "ct" then :container
  else :vm
  end
end

#usage_error(message) ⇒ Integer

Outputs usage error.

Parameters:

  • message (String)

    error message

Returns:

  • (Integer)

    exit code



206
207
208
209
# File 'lib/pvectl/commands/set_volume.rb', line 206

def usage_error(message)
  $stderr.puts "Error: #{message}"
  ExitCodes::USAGE_ERROR
end