Class: OsCtld::Commands::Container::LocalTransfer::Base

Inherits:
Logged
  • Object
show all
Includes:
OsCtl::Lib::Utils::Log, OsCtl::Lib::Utils::System
Defined in:
lib/osctld/commands/container/local_transfer/base.rb

Direct Known Subclasses

Cancel, Cleanup, Config, Rootfs, State, Sync

Instance Attribute Summary

Attributes inherited from Base

#client, #client_handler, #id, #opts

Instance Method Summary collapse

Methods inherited from Logged

#base_execute

Methods inherited from Base

#base_execute, #call_cmd, #call_cmd!, #error, #error!, #execute, handle, #handled, #indirect?, #initialize, #manipulate, #manipulation_holder, #ok, #progress, #request_stop, run, run!

Constructor Details

This class inherits a constructor from OsCtld::Commands::Base

Instance Method Details

#build_dataset_map(source_ct, target_ct) ⇒ Object (protected)



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 72

def build_dataset_map(source_ct, target_ct)
  root = LocalTransfer::Log::Dataset.new(
    relative_name: '/',
    source: source_ct.dataset.name,
    target: target_ct.dataset.name
  )

  children = source_ct.dataset.descendants.map do |src_ds|
    LocalTransfer::Log::Dataset.new(
      relative_name: src_ds.relative_name,
      source: src_ds.name,
      target: File.join(target_ct.dataset.name, src_ds.relative_name)
    )
  end

  [root, *children]
end

#cleanup_target_container!(log) ⇒ Object (protected)



173
174
175
176
177
178
179
180
181
182
183
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 173

def cleanup_target_container!(log)
  target = begin
    target_ct(log)
  rescue CommandFailed
    nil
  end
  return unless target

  builder = Container::Builder.new(target.new_run_conf, cmd: self)
  builder.cleanup(dataset: !log.opts.target_dataset_custom)
end

#clear_failed_state_snapshot(ct, log) ⇒ Object (protected)



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 144

def clear_failed_state_snapshot(ct, log)
  snap = log.state_snapshot
  return if snap.nil?

  progress("Removing failed cutover snapshot #{snap}")

  log.opts.datasets.each do |pair|
    zfs(:destroy, nil, "#{pair.source}@#{snap}", valid_rcs: [1])
    zfs(:destroy, nil, "#{pair.target}@#{snap}", valid_rcs: [1])
  end

  ct.exclusively do
    ct.local_transfer_log.state_snapshot = nil
    ct.save_config
  end
end

#complete_target!(log) ⇒ Object (protected)



56
57
58
59
60
61
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 56

def complete_target!(log)
  ct = ensure_target_staged_or_complete!(log)

  ct.state = :complete if ct.state == :staged
  ct
end

#destroy_local_transfer_snapshots(log) ⇒ Object (protected)



161
162
163
164
165
166
167
168
169
170
171
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 161

def destroy_local_transfer_snapshots(log)
  snaps = log.snapshots.dup
  snaps << log.state_snapshot if log.state_snapshot

  log.opts.datasets.each do |pair|
    snaps.reverse_each do |snap|
      zfs(:destroy, nil, "#{pair.source}@#{snap}", valid_rcs: [1])
      zfs(:destroy, nil, "#{pair.target}@#{snap}", valid_rcs: [1])
    end
  end
end

#ensure_target_staged_or_complete!(log) ⇒ Object (protected)



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 44

def ensure_target_staged_or_complete!(log)
  ct = target_ct(log)

  ct.exclusively do
    unless %i[staged stopped].include?(ct.state)
      error!('target container is not staged')
    end
  end

  ct
end

#findObject



13
14
15
16
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 13

def find
  ct = DB::Containers.find(opts[:id], opts[:pool])
  ct || error!('container not found')
end

#force_writeout(ct) ⇒ Object (protected)



133
134
135
136
137
138
139
140
141
142
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 133

def force_writeout(ct)
  return unless Daemon.get.config.writeout_dirtied_pages?

  begin
    ct.unmount(force: true)
  rescue SystemCommandFailed => e
    log(:warn, ct, "Unable to unmount dataset for writeback: #{e.message}")
    ct.mount(force: true)
  end
end

#operationObject (protected)

Raises:

  • (NotImplementedError)


20
21
22
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 20

def operation
  raise NotImplementedError
end

#require_local_transfer_log!(ct) ⇒ Object (protected)



24
25
26
27
28
29
30
31
32
33
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 24

def require_local_transfer_log!(ct)
  log = ct.local_transfer_log
  error!('invalid local transfer sequence') unless log

  unless log.opts.operation == operation
    error!("local transfer is for #{log.opts.operation}, not #{operation}")
  end

  log
end

#snapshot_datasets(log, snap) ⇒ Object (protected)



104
105
106
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 104

def snapshot_datasets(log, snap)
  zfs(:snapshot, nil, log.opts.datasets.map { |ds| "#{ds.source}@#{snap}" }.join(' '))
end

#snapshot_name(kind) ⇒ Object (protected)



99
100
101
102
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 99

def snapshot_name(kind)
  prefix = operation == :copy ? 'osctl-copy' : 'osctl-move'
  "#{prefix}-#{kind}-#{Time.now.to_i}-#{SecureRandom.hex(4)}"
end

#start_target!(log) ⇒ Object (protected)



63
64
65
66
67
68
69
70
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 63

def start_target!(log)
  call_cmd!(
    Commands::Container::Start,
    id: log.opts.target_id,
    pool: log.opts.target_pool,
    force: true
  )
end

#target_ct(log) ⇒ Object (protected)



39
40
41
42
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 39

def target_ct(log)
  pool = target_pool(log)
  DB::Containers.find(log.opts.target_id, pool) || error!('target container not found')
end

#target_pool(log) ⇒ Object (protected)



35
36
37
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 35

def target_pool(log)
  DB::Pools.find(log.opts.target_pool) || error!('target pool not found')
end

#transfer_dataset(pair, snapshot, from_snapshot: nil) ⇒ Object (protected)



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 108

def transfer_dataset(pair, snapshot, from_snapshot: nil)
  src = OsCtl::Lib::Zfs::Dataset.new(pair.source, base: pair.source)
  dst = OsCtl::Lib::Zfs::Dataset.new(pair.target, base: pair.target)

  progress("Copying dataset #{pair.relative_name}")

  stream = OsCtl::Lib::Zfs::Stream.new(
    src,
    snapshot,
    from_snapshot,
    intermediary: false
  )

  stream.progress do |total, _transfered, changed|
    progress(type: :progress, data: {
      time: Time.now.to_i,
      size: stream.size,
      transfered: total,
      changed:
    })
  end

  stream.send_recv(dst.name)
end

#validate_dataset_layout!(ct) ⇒ Object (protected)



90
91
92
93
94
95
96
97
# File 'lib/osctld/commands/container/local_transfer/base.rb', line 90

def validate_dataset_layout!(ct)
  expected = ct.local_transfer_log.opts.datasets.map(&:source).sort
  actual = ct.datasets.map(&:name).sort

  return if expected == actual

  error!('container dataset layout changed since transfer was prepared; cancel and start again')
end