Class: OsCtld::Container::DatasetBuilder

Inherits:
Object
  • Object
show all
Includes:
OsCtl::Lib::Utils::Log, OsCtl::Lib::Utils::System, Utils::SwitchUser
Defined in:
lib/osctld/container/dataset_builder.rb

Instance Method Summary collapse

Methods included from Utils::SwitchUser

#ct_attach, #ct_syscmd

Constructor Details

#initialize(opts = {}) ⇒ DatasetBuilder

Returns a new instance of DatasetBuilder.

Parameters:

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

Options Hash (opts):

  • :cmd (Command::Base)


12
13
14
# File 'lib/osctld/container/dataset_builder.rb', line 12

def initialize(opts = {})
  @builder_opts = opts
end

Instance Method Details

#copy_datasets(src, dst, from: nil) ⇒ String

Returns snapshot name.

Parameters:

  • src (Array<OsCtl::Lib::Zfs::Dataset>)
  • dst (Array<OsCtl::Lib::Zfs::Dataset>)
  • from (String, nil) (defaults to: nil)

    base snapshot

Returns:

  • (String)

    snapshot name



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/osctld/container/dataset_builder.rb', line 45

def copy_datasets(src, dst, from: nil)
  snap = "osctl-copy-#{from ? 'incr' : 'base'}-#{Time.now.to_i}"
  zfs(:snapshot, nil, src.map { |ds| "#{ds}@#{snap}" }.join(' '))

  zipped = src.zip(dst)

  zipped.each do |src_ds, dst_ds|
    progress("Copying dataset #{src_ds.relative_name}")
    syscmd("zfs send -c -p -L #{from ? "-i @#{from}" : ''} #{src_ds}@#{snap} "+
           "| zfs recv -F #{dst_ds}")
  end

  snap
end

#create_dataset(ds, opts = {}) ⇒ Object

Parameters:

  • ds (OsCtl::Lib::Zfs::Dataset)
  • opts (Hash) (defaults to: {})

    options

Options Hash (opts):

  • :uid_map (OsCtl::Lib::IdMap)
  • :gid_map (OsCtl::Lib::IdMap)
  • :parents (Boolean)


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/osctld/container/dataset_builder.rb', line 21

def create_dataset(ds, opts = {})
  zfs_opts = {
    properties: {
      canmount: 'noauto',
    },
  }
  zfs_opts[:parents] = true if opts[:parents]

  if opts[:uid_map]
    zfs_opts[:properties][:uidmap] = opts[:uid_map].map(&:to_s).join(',')
  end

  if opts[:gid_map]
    zfs_opts[:properties][:gidmap] = opts[:gid_map].map(&:to_s).join(',')
  end

  ds.create!(zfs_opts)
  ds.mount(recursive: true)
end

#from_local_archive(image, dir, opts = {}) ⇒ Object

Parameters:

  • image (String)

    image path

  • dir (String)

    dir to extract it to

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

    options

Options Hash (opts):

  • :distribution (String)
  • :version (String)


65
66
67
68
69
# File 'lib/osctld/container/dataset_builder.rb', line 65

def from_local_archive(image, dir, opts = {})
  progress('Extracting image')
  syscmd("tar -xzf #{image} -C #{dir}")
  shift_dataset
end

#from_stream(ds) ⇒ Object

Parameters:

  • ds (OsCtl::Lib::Zfs::Dataset)


72
73
74
75
76
77
78
79
80
81
82
# File 'lib/osctld/container/dataset_builder.rb', line 72

def from_stream(ds)
  progress('Writing image stream')

  IO.popen("exec zfs recv -F #{ds}", 'r+') do |io|
    yield(io)
  end

  if $?.exitstatus != 0
    fail "zfs recv failed with exit status #{$?.exitstatus}"
  end
end

#progress(msg) ⇒ Object (protected)



135
136
137
138
# File 'lib/osctld/container/dataset_builder.rb', line 135

def progress(msg)
  return unless @builder_opts[:cmd]
  @builder_opts[:cmd].send(:progress, msg)
end

#shift_dataset(ds, opts = {}) ⇒ Object

Parameters:

  • ds (OsCtl::Lib::Zfs::Dataset)
  • opts (Hash) (defaults to: {})

    options

Options Hash (opts):

  • :uid_map (OsCtl::Lib::IdMap)
  • :gid_map (OsCtl::Lib::IdMap)


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/osctld/container/dataset_builder.rb', line 88

def shift_dataset(ds, opts = {})
  progress('Configuring UID/GID mapping')

  set_opts = []

  if opts[:uid_map]
    set_opts << "\"uidmap=#{opts[:uid_map].map(&:to_s).join(',')}\""
  end

  if opts[:gid_map]
    set_opts << "\"gidmap=#{opts[:gid_map].map(&:to_s).join(',')}\""
  end

  if set_opts.empty?
    fail 'provide uid_map or gid_map'
  end

  zfs(:unmount, nil, ds, valid_rcs: [1])
  zfs(:set, set_opts.join(' '), ds)

  5.times do |i|
    zfs(:mount, nil, ds)

    f = Tempfile.create(['.ugid-map-test'], ds.mountpoint)
    f.close

    st = File.stat(f.path)
    File.unlink(f.path)

    mapped = false

    if opts[:uid_map] && st.uid == opts[:uid_map].ns_to_host(0)
      mapped = true
    elsif opts[:gid_map] && st.gid == opts[:gid_map].ns_to_host(0)
      mapped = true
    end

    return if mapped

    zfs(:unmount, nil, ds)
    sleep(1 + i)
  end

  fail 'unable to configure UID/GID mapping'
end