Class: Pvectl::Services::Snapshot

Inherits:
Object
  • Object
show all
Defined in:
lib/pvectl/services/snapshot.rb

Overview

Orchestrates snapshot operations.

Handles listing, creating, deleting and rolling back snapshots for VMs and containers with unified interface.

Examples:

Basic usage

service = Snapshot.new(
  snapshot_repo: snapshot_repo,
  resource_resolver: resolver,
  task_repo: task_repo
)
snapshots = service.list([100, 101])

Constant Summary collapse

DEFAULT_TIMEOUT =
60

Instance Method Summary collapse

Constructor Details

#initialize(snapshot_repo:, resource_resolver:, task_repo:, options: {}) ⇒ Snapshot

Creates a new Snapshot service.

Parameters:



27
28
29
30
31
32
# File 'lib/pvectl/services/snapshot.rb', line 27

def initialize(snapshot_repo:, resource_resolver:, task_repo:, options: {})
  @snapshot_repo = snapshot_repo
  @resolver = resource_resolver
  @task_repo = task_repo
  @options = options
end

Instance Method Details

#create(vmids, name:, description: nil, vmstate: false, node: nil) ⇒ Array<Models::OperationResult>

Creates snapshots for given VMIDs, or all cluster resources when vmids is empty.

When vmids is empty, creates snapshots for all resources in the cluster.

Parameters:

  • vmids (Array<Integer>)

    VM/container IDs (empty = all)

  • name (String)

    snapshot name

  • description (String, nil) (defaults to: nil)

    optional description

  • vmstate (Boolean) (defaults to: false)

    save VM memory state

  • node (String, nil) (defaults to: nil)

    filter by node name

Returns:



90
91
92
93
94
95
96
97
98
# File 'lib/pvectl/services/snapshot.rb', line 90

def create(vmids, name:, description: nil, vmstate: false, node: nil)
  resources = resolve_resources(vmids)
  resources = filter_by_node(resources, node)
  return [] if resources.empty?

  execute_multi(resources, :create) do |r|
    @snapshot_repo.create(r[:vmid], r[:node], r[:type], name: name, description: description, vmstate: vmstate)
  end
end

#delete(vmids, snapname, force: false, node: nil) ⇒ Array<Models::OperationResult>

Deletes snapshots from given VMIDs, or all cluster resources when vmids is empty.

When vmids is empty, deletes snapshots from all resources in the cluster.

Parameters:

  • vmids (Array<Integer>)

    VM/container IDs (empty = all)

  • snapname (String)

    snapshot name to delete

  • force (Boolean) (defaults to: false)

    force removal even if disk snapshot fails

  • node (String, nil) (defaults to: nil)

    filter by node name

Returns:



109
110
111
112
113
114
115
116
117
# File 'lib/pvectl/services/snapshot.rb', line 109

def delete(vmids, snapname, force: false, node: nil)
  resources = resolve_resources(vmids)
  resources = filter_by_node(resources, node)
  return [] if resources.empty?

  execute_multi(resources, :delete) do |r|
    @snapshot_repo.delete(r[:vmid], r[:node], r[:type], snapname, force: force)
  end
end

#delete_all(vmids, node: nil, force: false) ⇒ Array<Models::OperationResult>

Deletes ALL snapshots from given VMIDs.

When vmids is empty, deletes all snapshots from all resources in the cluster. Skips the “current” pseudo-snapshot.

Parameters:

  • vmids (Array<Integer>)

    VM/container IDs (empty = all)

  • node (String, nil) (defaults to: nil)

    filter by node name

  • force (Boolean) (defaults to: false)

    force removal even if disk snapshot fails

Returns:



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

def delete_all(vmids, node: nil, force: false)
  resources = resolve_resources(vmids)
  resources = filter_by_node(resources, node)
  return [] if resources.empty?

  results = []

  resources.each do |r|
    snapshots = @snapshot_repo.list(r[:vmid], r[:node], r[:type])
    snapshots.reject! { |s| s.name == "current" }

    snapshots.each do |snap|
      result = execute_single(r, :delete) do
        @snapshot_repo.delete(r[:vmid], r[:node], r[:type], snap.name, force: force)
      end
      results << result

      break if @options[:fail_fast] && result.failed?
    end

    break if @options[:fail_fast] && results.last&.failed?
  end

  results
end

#describe(vmids, name, node: nil) ⇒ Models::SnapshotDescription

Describes a snapshot by name across given VMIDs.

When vmids is empty, searches all resources in the cluster. Returns a SnapshotDescription with entries for each VM/CT that has the snapshot.

Parameters:

  • vmids (Array<Integer>)

    VM/container IDs (empty = search all)

  • name (String)

    snapshot name to find

  • node (String, nil) (defaults to: nil)

    filter by node name

Returns:

Raises:



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/pvectl/services/snapshot.rb', line 61

def describe(vmids, name, node: nil)
  resources = resolve_resources(vmids)
  resources = filter_by_node(resources, node)

  if resources.empty?
    message = vmids.empty? ? "no resources found in cluster" : "resource #{vmids.first} not found"
    raise ResourceNotFoundError, message
  end

  entries = build_describe_entries(resources, name)

  if entries.empty?
    message = vmids.empty? ? "snapshot '#{name}' not found in cluster" : "snapshot '#{name}' not found on VM #{vmids.join(', ')}"
    raise ResourceNotFoundError, message
  end

  Models::SnapshotDescription.new(entries: entries)
end

#list(vmids, node: nil) ⇒ Array<Models::Snapshot>

Lists snapshots for given VMIDs.

When vmids is empty, lists snapshots for all resources in the cluster.

Parameters:

  • vmids (Array<Integer>)

    VM/container IDs (empty = all)

  • node (String, nil) (defaults to: nil)

    filter by node name

Returns:



41
42
43
44
45
46
47
48
49
# File 'lib/pvectl/services/snapshot.rb', line 41

def list(vmids, node: nil)
  resources = resolve_resources(vmids)
  resources = filter_by_node(resources, node)
  return [] if resources.empty?

  resources.flat_map do |r|
    @snapshot_repo.list(r[:vmid], r[:node], r[:type])
  end
end

#rollback(vmid, snapname, start: false) ⇒ Models::OperationResult

Rolls back to a snapshot.

Parameters:

  • vmid (Integer)

    VM/container ID

  • snapname (String)

    snapshot name to rollback to

  • start (Boolean) (defaults to: false)

    start after rollback (LXC only)

Returns:



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/pvectl/services/snapshot.rb', line 160

def rollback(vmid, snapname, start: false)
  resource = @resolver.resolve(vmid)

  if resource.nil?
    return Models::OperationResult.new(
      resource: { vmid: vmid },
      operation: :rollback,
      success: false,
      error: "Resource #{vmid} not found"
    )
  end

  execute_single(resource, :rollback) do
    @snapshot_repo.rollback(resource[:vmid], resource[:node], resource[:type], snapname, start: start)
  end
end