Class: Pvectl::Services::Backup

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

Overview

Orchestrates backup operations.

Handles creating, listing, deleting, and restoring backups for VMs and containers with multi-ID support and error handling.

Examples:

Basic usage

service = Backup.new(
  backup_repo: backup_repo,
  resource_resolver: resolver,
  task_repo: task_repo
)
backups = service.list(vmid: 100)

Constant Summary collapse

DEFAULT_TIMEOUT =

5 minutes for backups

Returns:

  • (Integer)
300

Instance Method Summary collapse

Constructor Details

#initialize(backup_repo:, resource_resolver:, task_repo:, options: {}) ⇒ Backup

Creates a new Backup service.

Parameters:

  • backup_repo (Repositories::Backup)

    Backup repository

  • resource_resolver (Utils::ResourceResolver)

    Resource resolver

  • task_repo (Repositories::Task)

    Task repository

  • options (Hash) (defaults to: {})

    Options (timeout, async, fail_fast)

  • backup_repo: (Object)
  • resource_resolver: (Object)
  • task_repo: (Object)
  • options: (Hash[Symbol, untyped]) (defaults to: {})


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

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

Instance Method Details

#create(vmids, storage:, mode: "snapshot", compress: "zstd", notes: nil, protected: false) ⇒ Array<Models::OperationResult>

Creates backups for multiple VMs.

Parameters:

  • vmids (Array<Integer>)

    VM IDs

  • storage (String)

    target storage

  • mode (String) (defaults to: "snapshot")

    backup mode (snapshot/suspend/stop)

  • compress (String) (defaults to: "zstd")

    compression (zstd/gzip/lzo/0)

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

    backup notes

  • protected (Boolean) (defaults to: false)

    protect backup

  • storage: (String)
  • mode: (String) (defaults to: "snapshot")
  • compress: (String) (defaults to: "zstd")
  • notes: (String, nil) (defaults to: nil)
  • protected: (Boolean) (defaults to: false)

Returns:



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/pvectl/services/backup.rb', line 52

def create(vmids, storage:, mode: "snapshot", compress: "zstd", notes: nil, protected: false)
  resources = @resolver.resolve_multiple(vmids)
  return [] if resources.empty?

  execute_multi(resources, :create) do |resource|
    @backup_repo.create(
      resource[:vmid],
      resource[:node],
      storage: storage,
      mode: mode,
      compress: compress,
      notes: notes,
      protected: protected
    )
  end
end

#delete(volid) ⇒ Models::OperationResult

Deletes a backup.

Parameters:

  • volid (String)

    backup volume ID

Returns:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/pvectl/services/backup.rb', line 73

def delete(volid)
  node = find_node_for_volid(volid)

  upid = @backup_repo.delete(volid, node)

  if @options[:async]
    Models::OperationResult.new(
      resource: { volid: volid, node: node },
      operation: :delete,
      task_upid: upid,
      success: :pending
    )
  else
    task = @task_repo.wait(upid, timeout: timeout)
    Models::OperationResult.new(
      resource: { volid: volid, node: node },
      operation: :delete,
      task: task,
      success: task.successful?
    )
  end
rescue StandardError => e
  Models::OperationResult.new(
    resource: { volid: volid },
    operation: :delete,
    success: false,
    error: e.message
  )
end

#execute_multi(resources, operation) {|arg0| ... } ⇒ Array[Models::OperationResult]

Parameters:

  • resources (Array[Hash[Symbol, untyped]])
  • operation (Symbol)

Yields:

Yield Parameters:

  • arg0 (Hash[Symbol, untyped])

Yield Returns:

  • (String)

Returns:



152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/pvectl/services/backup.rb', line 152

def execute_multi(resources, operation)
  results = []

  resources.each do |resource|
    result = execute_single(resource, operation) { yield(resource) }
    results << result

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

  results
end

#execute_single(resource, operation) { ... } ⇒ Models::OperationResult

Parameters:

  • resource (Hash[Symbol, untyped])
  • operation (Symbol)

Yields:

Yield Returns:

  • (String)

Returns:



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/services/backup.rb', line 165

def execute_single(resource, operation)
  upid = yield

  if @options[:async]
    Models::OperationResult.new(
      resource: resource,
      operation: operation,
      task_upid: upid,
      success: :pending
    )
  else
    task = @task_repo.wait(upid, timeout: timeout)
    Models::OperationResult.new(
      resource: resource,
      operation: operation,
      task: task,
      success: task.successful?
    )
  end
rescue StandardError => e
  Models::OperationResult.new(
    resource: resource,
    operation: operation,
    success: false,
    error: e.message
  )
end

#find_node_for_volid(volid) ⇒ String

Finds the node for a backup by searching all backups.

Parameters:

  • volid (String)

    backup volume ID

Returns:

  • (String)

    node name

Raises:

  • (StandardError)

    if backup not found



202
203
204
205
206
# File 'lib/pvectl/services/backup.rb', line 202

def find_node_for_volid(volid)
  backups = @backup_repo.list
  backup = backups.find { |b| b.volid == volid }
  backup&.node || raise("Backup not found: #{volid}")
end

#list(vmid: nil, storage: nil) ⇒ Array<Models::Backup>

Lists backups with optional filtering.

Parameters:

  • vmid (Integer, nil) (defaults to: nil)

    filter by VM ID

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

    filter by storage

  • vmid: (Integer, nil) (defaults to: nil)
  • storage: (String, nil) (defaults to: nil)

Returns:



39
40
41
# File 'lib/pvectl/services/backup.rb', line 39

def list(vmid: nil, storage: nil)
  @backup_repo.list(vmid: vmid, storage: storage)
end

#restore(volid, vmid:, storage: nil, force: false, start: false, unique: false) ⇒ Models::OperationResult

Restores a backup to a VM/container.

Parameters:

  • volid (String)

    backup volume ID

  • vmid (Integer)

    target VM ID

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

    target storage

  • force (Boolean) (defaults to: false)

    overwrite existing

  • start (Boolean) (defaults to: false)

    start after restore

  • unique (Boolean) (defaults to: false)

    regenerate unique properties

  • vmid: (Integer)
  • storage: (String, nil) (defaults to: nil)
  • force: (Boolean) (defaults to: false)
  • start: (Boolean) (defaults to: false)
  • unique: (Boolean) (defaults to: false)

Returns:



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/pvectl/services/backup.rb', line 112

def restore(volid, vmid:, storage: nil, force: false, start: false, unique: false)
  node = find_node_for_volid(volid)

  upid = @backup_repo.restore(
    volid,
    node,
    vmid: vmid,
    storage: storage,
    force: force,
    start: start,
    unique: unique
  )

  if @options[:async]
    Models::OperationResult.new(
      resource: { volid: volid, vmid: vmid, node: node },
      operation: :restore,
      task_upid: upid,
      success: :pending
    )
  else
    task = @task_repo.wait(upid, timeout: timeout)
    Models::OperationResult.new(
      resource: { volid: volid, vmid: vmid, node: node },
      operation: :restore,
      task: task,
      success: task.successful?
    )
  end
rescue StandardError => e
  Models::OperationResult.new(
    resource: { volid: volid, vmid: vmid },
    operation: :restore,
    success: false,
    error: e.message
  )
end

#timeoutInteger

Returns:

  • (Integer)


193
194
195
# File 'lib/pvectl/services/backup.rb', line 193

def timeout
  @options[:timeout] || DEFAULT_TIMEOUT
end