Class: Pvectl::Services::CloneContainer

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

Overview

Orchestrates container clone operations.

Handles validation, auto-generation of CTID/hostname, and sync/async modes. Supports both full clones and linked clones (templates only).

Examples:

Full clone with auto-generated CTID

service = CloneContainer.new(container_repository: ct_repo, task_repository: task_repo)
result = service.execute(ctid: 100)

Linked clone to specific node

service = CloneContainer.new(container_repository: ct_repo, task_repository: task_repo)
result = service.execute(ctid: 100, linked: true, target_node: "pve2")

Async clone with custom timeout

service = CloneContainer.new(container_repository: ct_repo, task_repository: task_repo, options: { async: true })
result = service.execute(ctid: 100, new_ctid: 200, hostname: "web-clone")

Constant Summary collapse

DEFAULT_TIMEOUT =
300
START_TIMEOUT =

Returns Default timeout for start operations (seconds).

Returns:

  • (Integer)

    Default timeout for start operations (seconds)

60

Instance Method Summary collapse

Constructor Details

#initialize(container_repository:, task_repository:, options: {}) ⇒ CloneContainer

Creates a new CloneContainer service.

Parameters:



33
34
35
36
37
# File 'lib/pvectl/services/clone_container.rb', line 33

def initialize(container_repository:, task_repository:, options: {})
  @container_repository = container_repository
  @task_repository = task_repository
  @options = options
end

Instance Method Details

#execute(ctid:, node: nil, new_ctid: nil, hostname: nil, target_node: nil, storage: nil, linked: false, pool: nil, description: nil, config_params: {}) ⇒ Models::ContainerOperationResult

Executes clone operation.

Performs a two-step flow: clone the container first, then optionally apply config updates via PUT /nodes/node/lxc/ctid/config.

Parameters:

  • ctid (Integer)

    Source container identifier

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

    Source node (auto-detected from container if nil)

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

    New CTID (auto-selected if nil)

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

    Hostname for clone (auto-generated if nil)

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

    Target node for clone

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

    Target storage

  • linked (Boolean) (defaults to: false)

    Linked clone (default: false, requires template)

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

    Resource pool

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

    Description

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

    Container config parameters to apply after clone

Returns:



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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/pvectl/services/clone_container.rb', line 55

def execute(ctid:, node: nil, new_ctid: nil, hostname: nil, target_node: nil,
            storage: nil, linked: false, pool: nil, description: nil,
            config_params: {})
  source_ct = @container_repository.get(ctid)
  return container_not_found_error(ctid) unless source_ct

  if linked && !source_ct.template?
    return linked_clone_error(source_ct)
  end

  node ||= source_ct.node
  new_ctid ||= @container_repository.next_available_ctid
  hostname ||= generate_hostname(source_ct)

  clone_options = build_clone_options(
    hostname: hostname, target_node: target_node, storage: storage,
    linked: linked, pool: pool, description: description
  )

  upid = @container_repository.clone(ctid, node, new_ctid, clone_options)
  resource_info = { new_ctid: new_ctid, hostname: hostname, node: target_node || node }

  if @options[:async]
    Models::ContainerOperationResult.new(
      container: source_ct, operation: :clone,
      task_upid: upid, success: :pending,
      resource: resource_info
    )
  else
    task = @task_repository.wait(upid, timeout: timeout)

    unless task.successful?
      return Models::ContainerOperationResult.new(
        container: source_ct, operation: :clone,
        task: task, success: task.successful?,
        resource: resource_info
      )
    end

    if config_params.any?
      apply_config_update(source_ct, new_ctid, resource_info[:node], config_params, resource_info)
    else
      start_container(new_ctid, resource_info[:node]) if @options[:start]
      Models::ContainerOperationResult.new(
        container: source_ct, operation: :clone,
        task: task, success: true,
        resource: resource_info
      )
    end
  end
rescue StandardError => e
  Models::ContainerOperationResult.new(
    container: source_ct, operation: :clone,
    success: false, error: e.message
  )
end