Class: Pvectl::Commands::DeleteSnapshot

Inherits:
Object
  • Object
show all
Defined in:
lib/pvectl/commands/delete_snapshot.rb,
sig/pvectl/commands/delete_snapshot.rbs

Overview

Handler for the pvectl delete snapshot sub-command.

Deletes snapshots from VMs/containers. Snapshot name is the first positional argument, or use --all to delete ALL snapshots. VMIDs are specified via --vmid flag. Without --vmid, operates cluster-wide.

Examples:

Delete named snapshot

pvectl delete snapshot before-upgrade --vmid 100 --yes

Delete all snapshots from a VM

pvectl delete snapshot --all --vmid 100 --yes

Delete named snapshot cluster-wide

pvectl delete snapshot before-upgrade --yes

Constant Summary collapse

VMID_PATTERN =
/\A[1-9]\d{0,8}\z/

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args, options, global_options) ⇒ DeleteSnapshot

Initializes a delete snapshot command.



82
83
84
85
86
87
88
89
90
# File 'lib/pvectl/commands/delete_snapshot.rb', line 82

def initialize(args, options, global_options)
  @args = Array(args)
  @options = options
  @global_options = global_options
  @snapshot_name = @args.first
  @vmids = parse_vmids(options[:vmid])
  @node = options[:node]
  @delete_all = options[:all] || false
end

Class Method Details

.execute(args, options, global_options) ⇒ Integer

Executes the delete snapshot command.



73
74
75
# File 'lib/pvectl/commands/delete_snapshot.rb', line 73

def self.execute(args, options, global_options)
  new(args, options, global_options).execute
end

.register_subcommand(parent) ⇒ void

This method returns an undefined value.

Registers as a sub-command under the parent delete command.



27
28
29
30
31
32
33
34
35
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
# File 'lib/pvectl/commands/delete_snapshot.rb', line 27

def self.register_subcommand(parent)
  parent.desc "Delete snapshots from VMs or containers"
  parent.long_desc "    Delete snapshots from VMs and containers.\n\n    EXAMPLES\n      Delete a specific snapshot from a VM:\n        $ pvectl delete snapshot before-upgrade --vmid 100 --yes\n\n      Delete a snapshot from all VMs that have it:\n        $ pvectl delete snapshot before-upgrade --yes\n\n      Delete ALL snapshots from a specific VM:\n        $ pvectl delete snapshot --all --vmid 100 --yes\n\n      Delete ALL snapshots cluster-wide:\n        $ pvectl delete snapshot --all --yes\n\n    NOTES\n      Snapshot deletion is irreversible.\n\n      --all deletes every snapshot, not just the named one. Use with\n      extreme caution, especially without --vmid.\n\n    SEE ALSO\n      pvectl help create snapshot Create snapshots\n      pvectl help rollback        Rollback to a snapshot\n      pvectl help get snapshots   List existing snapshots\n  HELP\n  parent.command :snapshot do |s|\n    s.desc \"VM/CT ID (repeatable)\"\n    s.flag [:vmid], arg_name: \"VMID\", multiple: true\n\n    s.action do |global_options, options, args|\n      exit_code = execute(args, options, global_options)\n      exit exit_code if exit_code != 0\n    end\n  end\nend\n"

Instance Method Details

#confirm_operationBoolean

Confirms operation with user prompt.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/pvectl/commands/delete_snapshot.rb', line 129

def confirm_operation
  return true if @options[:yes]

  if @delete_all
    if @vmids.empty?
      $stdout.puts "You are about to delete ALL snapshots from ALL VMs/CTs in the cluster."
    else
      $stdout.puts "You are about to delete ALL snapshots from #{@vmids.size} VMs:"
      @vmids.each { |vmid| $stdout.puts "  - #{vmid}" }
    end
  else
    if @vmids.empty?
      $stdout.puts "You are about to delete snapshot '#{@snapshot_name}' from ALL VMs/CTs in the cluster."
    elsif @vmids.size == 1
      $stdout.puts "You are about to delete snapshot '#{@snapshot_name}' from VM #{@vmids.first}."
    else
      $stdout.puts "You are about to delete snapshot '#{@snapshot_name}' from #{@vmids.size} VMs:"
      @vmids.each { |vmid| $stdout.puts "  - #{vmid}" }
    end
  end
  $stdout.puts ""
  $stdout.print "Proceed? [y/N]: "

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

#determine_exit_code(results) ⇒ Integer

Determines exit code.



231
232
233
234
235
236
# File 'lib/pvectl/commands/delete_snapshot.rb', line 231

def determine_exit_code(results)
  return ExitCodes::SUCCESS if results.all?(&:successful?)
  return ExitCodes::SUCCESS if results.all?(&:pending?)

  ExitCodes::GENERAL_ERROR
end

#executeInteger

Executes the delete snapshot command.



95
96
97
98
99
100
101
102
103
# File 'lib/pvectl/commands/delete_snapshot.rb', line 95

def execute
  return usage_error("Snapshot name or --all required") if @snapshot_name.nil? && !@delete_all
  return usage_error("Cannot use --all with snapshot name") if @snapshot_name && @delete_all
  return usage_error("Invalid VMID: #{invalid_vmid}") if invalid_vmid

  return ExitCodes::SUCCESS unless confirm_operation

  perform_operation
end

#invalid_vmidString?

Finds first invalid VMID in options.



120
121
122
123
124
# File 'lib/pvectl/commands/delete_snapshot.rb', line 120

def invalid_vmid
  return nil if @options[:vmid].nil? || @options[:vmid].empty?

  Array(@options[:vmid]).find { |v| !VMID_PATTERN.match?(v.to_s) }
end

#load_configvoid

This method returns an undefined value.

Loads configuration.



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

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

#output_results(results) ⇒ void

This method returns an undefined value.

Outputs operation results.



217
218
219
220
221
222
223
224
225
# File 'lib/pvectl/commands/delete_snapshot.rb', line 217

def output_results(results)
  presenter = Pvectl::Presenters::SnapshotOperationResult.new
  format = @global_options[:output] || "table"
  color_flag = @global_options[:color]

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

#parse_vmids(vmid_values) ⇒ Array<Integer>

Parses --vmid flag values to integer array.



111
112
113
114
115
# File 'lib/pvectl/commands/delete_snapshot.rb', line 111

def parse_vmids(vmid_values)
  return [] if vmid_values.nil? || vmid_values.empty?

  Array(vmid_values).map(&:to_i)
end

#perform_operationInteger

Performs the snapshot deletion operation.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/pvectl/commands/delete_snapshot.rb', line 159

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

  snapshot_repo = Pvectl::Repositories::Snapshot.new(connection)
  resolver = Pvectl::Utils::ResourceResolver.new(connection)
  task_repo = Pvectl::Repositories::Task.new(connection)

  service = Pvectl::Services::Snapshot.new(
    snapshot_repo: snapshot_repo,
    resource_resolver: resolver,
    task_repo: task_repo,
    options: service_options
  )

  results = if @delete_all
    service.delete_all(@vmids, node: @node, force: @options[:force] || false)
  else
    service.delete(@vmids, @snapshot_name, force: @options[:force] || false, node: @node)
  end

  output_results(results)
  determine_exit_code(results)
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

#service_optionsHash

Builds service options.



205
206
207
208
209
210
211
# File 'lib/pvectl/commands/delete_snapshot.rb', line 205

def service_options
  opts = {}
  opts[:timeout] = @options[:timeout] if @options[:timeout]
  opts[:async] = true if @options[:async]
  opts[:fail_fast] = true if @options[:"fail-fast"]
  opts
end

#usage_error(message) ⇒ Integer

Outputs usage error.



242
243
244
245
# File 'lib/pvectl/commands/delete_snapshot.rb', line 242

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