Class: OsCtld::Mount::SharedDir

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils::SwitchUser

#ct_attach, #ct_syscmd

Constructor Details

#initialize(ct) ⇒ SharedDir

Returns a new instance of SharedDir.



11
12
13
# File 'lib/osctld/mount/shared_dir.rb', line 11

def initialize(ct)
  @ct = ct
end

Instance Attribute Details

#ctObject (readonly, protected)

Returns the value of attribute ct.



120
121
122
# File 'lib/osctld/mount/shared_dir.rb', line 120

def ct
  @ct
end

Instance Method Details

#cleanup_pushed(dir) ⇒ Object

Cleanup after #map_and_push

Parameters:

  • dir (String)


82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/osctld/mount/shared_dir.rb', line 82

def cleanup_pushed(dir)
  host_path = host_path_for(dir)

  syscmd("umount \"#{host_path}\"", valid_rcs: [32]) # 32 = not mounted

  begin
    Dir.rmdir(host_path)
  rescue Errno::ENOENT
    # pass
  end

  nil
end

#createObject

Prepare the shared mount directory on the host



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/osctld/mount/shared_dir.rb', line 16

def create
  dir = Pathname.new(path)

  unless dir.exist?
    dir.mkdir
    syscmd("mount --bind \"#{dir}\" \"#{dir}\"")
    syscmd("mount --make-rshared \"#{dir}\"")
  end

  create_readme unless File.exist?(readme_path)
end

#create_readmeObject (protected)



126
127
128
129
130
131
132
133
134
135
# File 'lib/osctld/mount/shared_dir.rb', line 126

def create_readme
  File.write(
    readme_path,
    <<~END
      Directory `#{File.join('/', mountpoint)}` is used by osctl from vpsAdminOS to
      propagate new mounts into this container. Do not remove nor unmount this
      directory, or you'll have to restart your container to create new mounts!
    END
  )
end

#dup(new_ct) ⇒ Object



112
113
114
115
116
# File 'lib/osctld/mount/shared_dir.rb', line 112

def dup(new_ct)
  ret = super()
  ret.instance_variable_set('@ct', new_ct)
  ret
end

#host_path_for(dir) ⇒ String

Returns:

  • (String)


97
98
99
# File 'lib/osctld/mount/shared_dir.rb', line 97

def host_path_for(dir)
  File.join(path, Digest::SHA2.hexdigest(dir))
end

#map_and_push(dir, ns_pid) ⇒ Object

Bind-mount path with ID-mapping and push it through the shared directory

Parameters:

  • dir (String)
  • ns_pid (Integer)
  • path (String)

    to the mountpoint, same in both init and ct mount namespaces



71
72
73
74
75
76
77
78
# File 'lib/osctld/mount/shared_dir.rb', line 71

def map_and_push(dir, ns_pid)
  host_path = host_path_for(dir)

  Dir.mkdir(host_path)
  syscmd("mount --bind -o X-mount.idmap=/proc/#{ns_pid}/ns/user #{dir} #{host_path}")

  host_path
end

#mountpointString

Mountpoint relative to the container’s rootfs

Returns:

  • (String)


108
109
110
# File 'lib/osctld/mount/shared_dir.rb', line 108

def mountpoint
  'dev/.osctl-mount-helper'
end

#pathString

Returns:

  • (String)


102
103
104
# File 'lib/osctld/mount/shared_dir.rb', line 102

def path
  File.join(ct.pool.mount_dir, ct.id)
end

#propagate(mnt) ⇒ Object

Propagate a new mount inside the container via the shared directory

Parameters:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/osctld/mount/shared_dir.rb', line 38

def propagate(mnt)
  # Bind-mount the new mount into the shared directory
  host_path = host_path_for(mnt.mountpoint)

  Dir.mkdir(host_path)

  opts =
    if ct.map_mode == 'native' && mnt.map_ids
      "-o X-mount.idmap=/proc/#{ct.init_pid}/ns/user"
    end

  syscmd("mount --bind #{opts} \"#{mnt.fs}\" \"#{host_path}\"")

  # Move the mount inside the container to the right place
  begin
    ContainerControl::Commands::Mount.run!(
      ct,
      shared_dir: File.join('/', mountpoint),
      src: File.basename(host_path),
      dst: File.join('/', mnt.mountpoint)
    )
  rescue ContainerControl::Error => e
    log(:warn, ct, "Failed to mount #{mnt.mountpoint} at runtime: #{e.message}")
  end

  syscmd("umount \"#{host_path}\"")
  Dir.rmdir(host_path)
end

#readme_pathObject (protected)



122
123
124
# File 'lib/osctld/mount/shared_dir.rb', line 122

def readme_path
  File.join(path, 'README.txt')
end

#removeObject

Remove the shared mount directory from the host



29
30
31
32
33
34
# File 'lib/osctld/mount/shared_dir.rb', line 29

def remove
  dir = Pathname.new(path)
  syscmd("umount -f \"#{dir}\"", valid_rcs: [32]) # 32 = not mounted
  FileUtils.rm_f(readme_path)
  dir.rmdir if dir.exist?
end