Class: OsCtld::Container
- Inherits:
-
Object
- Object
- OsCtld::Container
- Includes:
- OsCtl::Lib::Utils::File, OsCtl::Lib::Utils::Log, OsCtl::Lib::Utils::System, Assets::Definition, Lockable, Manipulable, Utils::SwitchUser
- Defined in:
- lib/osctld/container.rb
Defined Under Namespace
Modules: Adaptor, Hooks Classes: Builder, DatasetBuilder, Hints, Impermanence, Importer, LxcConfig, RawConfigs, Recovery, RunConfiguration, RunId, StartMenu
Constant Summary collapse
- MAP_MODES =
%w[native zfs].freeze
- DEFAULT_START_TIMEOUT =
120- DEFAULT_STOP_TIMEOUT =
300
Instance Attribute Summary collapse
-
#apparmor ⇒ Object
Returns the value of attribute apparmor.
-
#arch ⇒ Object
Returns the value of attribute arch.
-
#attrs ⇒ Object
Returns the value of attribute attrs.
-
#autostart ⇒ Object
Returns the value of attribute autostart.
-
#cgparams ⇒ Object
Returns the value of attribute cgparams.
-
#cpu_package ⇒ Object
Returns the value of attribute cpu_package.
-
#dataset ⇒ Object
Returns the value of attribute dataset.
-
#devices ⇒ Object
Returns the value of attribute devices.
-
#distribution ⇒ Object
Returns the value of attribute distribution.
-
#dns_resolvers ⇒ Object
Returns the value of attribute dns_resolvers.
-
#ephemeral ⇒ Object
(also: #ephemeral?)
Returns the value of attribute ephemeral.
-
#group ⇒ Object
Returns the value of attribute group.
-
#hints ⇒ Object
readonly
Returns the value of attribute hints.
-
#hostname ⇒ Object
Returns the value of attribute hostname.
-
#id ⇒ Object
Returns the value of attribute id.
-
#impermanence ⇒ Object
Returns the value of attribute impermanence.
-
#init_cmd ⇒ Object
Returns the value of attribute init_cmd.
-
#local_transfer_log ⇒ Object
Returns the value of attribute local_transfer_log.
-
#lxc_config ⇒ Object
Returns the value of attribute lxc_config.
-
#map_mode ⇒ Object
Returns the value of attribute map_mode.
-
#mounted ⇒ Object
protected
Returns the value of attribute mounted.
-
#mounts ⇒ Object
Returns the value of attribute mounts.
-
#nesting ⇒ Object
Returns the value of attribute nesting.
-
#netifs ⇒ Object
Returns the value of attribute netifs.
-
#next_run_conf ⇒ Object
readonly
Returns the value of attribute next_run_conf.
-
#pool ⇒ Object
Returns the value of attribute pool.
-
#prlimits ⇒ Object
Returns the value of attribute prlimits.
-
#raw_configs ⇒ Object
readonly
Returns the value of attribute raw_configs.
-
#run_conf ⇒ Object
readonly
Returns the value of attribute run_conf.
-
#seccomp_profile ⇒ Object
Returns the value of attribute seccomp_profile.
-
#send_log ⇒ Object
Returns the value of attribute send_log.
-
#start_menu ⇒ Object
Returns the value of attribute start_menu.
-
#state ⇒ Object
Returns the value of attribute state.
-
#user ⇒ Object
Returns the value of attribute user.
-
#variant ⇒ Object
Returns the value of attribute variant.
-
#vendor ⇒ Object
Returns the value of attribute vendor.
-
#version ⇒ Object
Returns the value of attribute version.
Class Method Summary collapse
Instance Method Summary collapse
- #abs_apply_cgroup_path(subsystem) ⇒ Object
- #abs_cgroup_path(subsystem) ⇒ Object
- #assets ⇒ Object
- #base_cgroup_path ⇒ Object
- #can_dist_configure_network? ⇒ Boolean
- #can_start? ⇒ Boolean
- #cgroup_path ⇒ Object
- #chgrp(grp, missing_devices: nil) ⇒ Object
- #chown(user) ⇒ Object
- #clear_start_menu ⇒ Object
-
#clone_from(_ct, id, opts = {}) ⇒ Object
protected
Change the container so that it becomes a clone of ‘ct` with a different id.
- #close_local_transfer_log(save: true) ⇒ Object
- #close_send_log(save: true) ⇒ Object
- #config_path ⇒ Object
- #configure(distribution, version, arch) ⇒ Object
- #configure_bashrc ⇒ Object
-
#current_state ⇒ Symbol
Fetch current container state by forking into it.
-
#datasets ⇒ Array<OsCtl::Lib::Zfs::Dataset>
Return a list of all container datasets.
- #default_init_cmd ⇒ Object protected
- #default_seccomp_profile ⇒ Object protected
- #dir ⇒ Object
-
#dump_config ⇒ Object
Dump to config.
-
#dup(id, opts = {}) ⇒ Object
Duplicate the container with a different ID.
-
#each_dataset {|ds| ... } ⇒ Object
Iterate over all container datasets.
-
#ensure_run_conf ⇒ Container::RunConfiguration
Call #init_run_conf unless #run_conf is already set.
- #entry_cgroup_path ⇒ Object
-
#export ⇒ Object
Export to clients.
-
#find_cpu_limit(parents: true) ⇒ Integer?
CPU limit in percent (100 % for one CPU).
-
#find_memory_limit(parents: true) ⇒ Integer?
Memory limit in bytes.
-
#find_swap_limit(parents: true) ⇒ Integer?
Swap limit in bytes.
- #forget_past_run_conf ⇒ Object
- #format_exec_init_cmd ⇒ Object
- #format_user_init_cmd ⇒ Object
-
#fresh_state ⇒ Symbol
Fetch current state if the state is not known, otherwise return the known state.
- #get_past_run_conf ⇒ Container::RunConfiguration?
- #get_run_conf ⇒ Container::RunConfiguration
- #gid_map ⇒ Object
- #ident ⇒ Object
- #init_pid ⇒ Object
-
#init_run_conf ⇒ Object
This must be called on container start.
-
#initialize(pool, id, user = nil, group = nil, dataset = nil, opts = {}) ⇒ Container
constructor
A new instance of Container.
- #load_config_file(path = nil) ⇒ Object protected
- #load_config_hash(cfg, init_devices: true, dataset_cache: nil) ⇒ Object protected
- #load_config_string(str) ⇒ Object protected
- #log_path ⇒ Object
- #log_type ⇒ Object
- #lxc_dir(user: nil, group: nil) ⇒ Object
- #lxc_home(user: nil, group: nil) ⇒ Object
- #manipulation_resource ⇒ Object
-
#mount(force: false) ⇒ Object
Mount the container’s dataset.
-
#mounted?(force: false) ⇒ Boolean
Check if the container’s dataset is mounted.
- #new_run_conf ⇒ Container::RunConfiguration
- #open_local_transfer_log(role, opts = {}) ⇒ Object
- #open_send_log(role, token, opts = {}) ⇒ Object
- #parse_yaml ⇒ Object protected
-
#patch_config(new_config) ⇒ Object
Update keys/values from ‘new_config` in the container’s config.
-
#read_hostname ⇒ String?
Read hostname from a running container.
-
#reconfigure ⇒ Object
Regenerate LXC config.
- #reload_config ⇒ Object
- #replace_config(config) ⇒ Object
- #root_host_gid ⇒ Object
- #root_host_uid ⇒ Object
- #rootfs ⇒ Object
- #running? ⇒ Boolean
- #save_config ⇒ Object
- #set(opts) ⇒ Object
- #set_next_run_conf(next_run_conf) ⇒ Object
- #setup_start_menu ⇒ Object
- #starting ⇒ Object
- #stopped ⇒ Object
- #syslogns_tag ⇒ Object
- #transfer_in_progress? ⇒ Boolean
- #transfer_log ⇒ Object
- #uid_map ⇒ Object
-
#unmount(force: false) ⇒ Object
Unmount the container’s dataset.
-
#unregister ⇒ Object
Unregister the container from internal uses in osctld, e.g.
- #unset(opts) ⇒ Object
- #update_hints ⇒ Object
- #user_hook_script_dir ⇒ Object
- #wrapper_cgroup_path ⇒ Object
Methods included from Utils::SwitchUser
Methods included from Assets::Definition
Methods included from Manipulable
#acquire_manipulation_lock, #init_manipulable, #is_being_manipulated?, #manipulate, #manipulated_by, #release_manipulation_lock
Methods included from Lockable
#exclusively, included, #inclusively, #init_lock, #lock, #unlock
Constructor Details
#initialize(pool, id, user = nil, group = nil, dataset = nil, opts = {}) ⇒ Container
Returns a new instance of Container.
49 50 51 52 53 54 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 |
# File 'lib/osctld/container.rb', line 49 def initialize(pool, id, user = nil, group = nil, dataset = nil, opts = {}) init_lock init_manipulable opts[:load] = true unless opts.has_key?(:load) if (user.nil? || group.nil?) && !opts[:load] raise ArgumentError, 'either set load: true or provide user and group' end @pool = pool @id = id @user = user @group = group @dataset = dataset @map_mode = opts[:map_mode] @state = opts[:staged] ? :staged : :unknown @local_transfer_log = nil @ephemeral = false @netifs = NetInterface::Manager.new(self) @cgparams = nil @devices = nil @prlimits = nil @mounts = nil @hostname = nil @dns_resolvers = nil @nesting = false @cpu_package = 'auto' @seccomp_profile = nil @apparmor = AppArmor.new(self) @lxc_config = Container::LxcConfig.new(self) @init_cmd = nil @raw_configs = Container::RawConfigs.new @attrs = Attributes.new @run_conf = nil @hints = Container::Hints.new(self) return unless opts[:load] load_opts = { init_devices: !opts.has_key?(:devices) || opts[:devices], dataset_cache: opts[:dataset_cache] } if opts[:load_from] load_config_string(opts[:load_from], **load_opts) else load_config_file(config_path, **load_opts) end end |
Instance Attribute Details
#apparmor ⇒ Object
Returns the value of attribute apparmor
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def apparmor @apparmor end |
#arch ⇒ Object
Returns the value of attribute arch
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def arch @arch end |
#attrs ⇒ Object
Returns the value of attribute attrs
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def attrs @attrs end |
#autostart ⇒ Object
Returns the value of attribute autostart
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def autostart @autostart end |
#cgparams ⇒ Object
Returns the value of attribute cgparams
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def cgparams @cgparams end |
#cpu_package ⇒ Object
Returns the value of attribute cpu_package
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def cpu_package @cpu_package end |
#dataset ⇒ Object
Returns the value of attribute dataset
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def dataset @dataset end |
#devices ⇒ Object
Returns the value of attribute devices
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def devices @devices end |
#distribution ⇒ Object
Returns the value of attribute distribution
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def distribution @distribution end |
#dns_resolvers ⇒ Object
Returns the value of attribute dns_resolvers
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def dns_resolvers @dns_resolvers end |
#ephemeral ⇒ Object Also known as: ephemeral?
Returns the value of attribute ephemeral
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def ephemeral @ephemeral end |
#group ⇒ Object
Returns the value of attribute group
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def group @group end |
#hints ⇒ Object (readonly)
Returns the value of attribute hints
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def hints @hints end |
#hostname ⇒ Object
Returns the value of attribute hostname
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def hostname @hostname end |
#id ⇒ Object
Returns the value of attribute id
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def id @id end |
#impermanence ⇒ Object
Returns the value of attribute impermanence
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def impermanence @impermanence end |
#init_cmd ⇒ Object
Returns the value of attribute init_cmd
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def init_cmd @init_cmd end |
#local_transfer_log ⇒ Object
Returns the value of attribute local_transfer_log
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def local_transfer_log @local_transfer_log end |
#lxc_config ⇒ Object
Returns the value of attribute lxc_config
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def lxc_config @lxc_config end |
#map_mode ⇒ Object
Returns the value of attribute map_mode
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def map_mode @map_mode end |
#mounted ⇒ Object (protected)
Returns the value of attribute mounted
915 916 917 |
# File 'lib/osctld/container.rb', line 915 def mounted @mounted end |
#mounts ⇒ Object
Returns the value of attribute mounts
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def mounts @mounts end |
#nesting ⇒ Object
Returns the value of attribute nesting
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def nesting @nesting end |
#netifs ⇒ Object
Returns the value of attribute netifs
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def netifs @netifs end |
#next_run_conf ⇒ Object (readonly)
Returns the value of attribute next_run_conf
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def next_run_conf @next_run_conf end |
#pool ⇒ Object
Returns the value of attribute pool
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def pool @pool end |
#prlimits ⇒ Object
Returns the value of attribute prlimits
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def prlimits @prlimits end |
#raw_configs ⇒ Object (readonly)
Returns the value of attribute raw_configs
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def raw_configs @raw_configs end |
#run_conf ⇒ Object (readonly)
Returns the value of attribute run_conf
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def run_conf @run_conf end |
#seccomp_profile ⇒ Object
Returns the value of attribute seccomp_profile
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def seccomp_profile @seccomp_profile end |
#send_log ⇒ Object
Returns the value of attribute send_log
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def send_log @send_log end |
#start_menu ⇒ Object
Returns the value of attribute start_menu
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def @start_menu end |
#state ⇒ Object
Returns the value of attribute state
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def state @state end |
#user ⇒ Object
Returns the value of attribute user
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def user @user end |
#variant ⇒ Object
Returns the value of attribute variant
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def variant @variant end |
#vendor ⇒ Object
Returns the value of attribute vendor
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def vendor @vendor end |
#version ⇒ Object
Returns the value of attribute version
27 28 29 |
# File 'lib/osctld/container.rb', line 27 def version @version end |
Class Method Details
.default_dataset(pool, id, dataset_cache: nil) ⇒ Object
22 23 24 25 |
# File 'lib/osctld/container.rb', line 22 def self.default_dataset(pool, id, dataset_cache: nil) name = File.join(pool.ct_ds, id) OsCtl::Lib::Zfs::Dataset.new(name, base: name, cache: dataset_cache) end |
Instance Method Details
#abs_apply_cgroup_path(subsystem) ⇒ Object
486 487 488 |
# File 'lib/osctld/container.rb', line 486 def abs_apply_cgroup_path(subsystem) CGroup.abs_cgroup_path(subsystem, base_cgroup_path) end |
#abs_cgroup_path(subsystem) ⇒ Object
482 483 484 |
# File 'lib/osctld/container.rb', line 482 def abs_cgroup_path(subsystem) CGroup.abs_cgroup_path(subsystem, cgroup_path) end |
#assets ⇒ Object
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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 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 192 193 194 195 196 |
# File 'lib/osctld/container.rb', line 122 def assets define_assets do |add| # Datasets add.dataset( dataset.to_s, desc: "Container's rootfs dataset", uidmap: map_mode == 'zfs' ? uid_map.map(&:to_a) : nil, gidmap: map_mode == 'zfs' ? gid_map.map(&:to_a) : nil, properties: if map_mode == 'native' { 'uidmap' => 'none', 'gidmap' => 'none' } end, user: map_mode == 'zfs' ? root_host_uid : 0, group: map_mode == 'zfs' ? root_host_gid : 0, mode: 0o770, validate_if: mounted? ) # Directories and files add.directory( rootfs, desc: "Container's rootfs", user: map_mode == 'zfs' ? root_host_uid : 0, group: map_mode == 'zfs' ? root_host_gid : 0, mode_bit_and: 0o111, # has all executable bits set validate_if: mounted? ) add.directory( user_hook_script_dir, desc: 'User supplied script hooks', user: 0, group: 0, mode: 0o700 ) add.directory( lxc_dir, desc: 'LXC configuration', user: 0, group: user.ugid, mode: 0o750 ) lxc_config.assets(add) add.file( File.join(lxc_dir, '.bashrc'), desc: 'Shell configuration file for osctl ct su', user: 0, group: 0, mode: 0o644 ) add.file( config_path, desc: 'Container config for osctld', user: 0, group: 0, mode: 0o400 ) add.file( log_path, desc: 'LXC log file', user: 0, group: user.ugid, mode: 0o660 ) run_conf.assets(add) if run_conf devices.assets(add) end end |
#base_cgroup_path ⇒ Object
466 467 468 |
# File 'lib/osctld/container.rb', line 466 def base_cgroup_path inclusively { File.join(group.full_cgroup_path(user), "ct.#{id}") } end |
#can_dist_configure_network? ⇒ Boolean
401 402 403 404 405 406 407 |
# File 'lib/osctld/container.rb', line 401 def can_dist_configure_network? inclusively do next false if netifs.detect { |netif| !netif.can_run_distconfig? } true end end |
#can_start? ⇒ Boolean
372 373 374 |
# File 'lib/osctld/container.rb', line 372 def can_start? inclusively { state != :staged && state != :error && pool.active? } end |
#cgroup_path ⇒ Object
470 471 472 |
# File 'lib/osctld/container.rb', line 470 def cgroup_path File.join(base_cgroup_path, 'user-owned') end |
#chgrp(grp, missing_devices: nil) ⇒ Object
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/osctld/container.rb', line 308 def chgrp(grp, missing_devices: nil) self.group = grp case missing_devices when 'provide' devices.ensure_all devices.init when 'remove' devices.remove_missing devices.init when 'check' devices.check_all_available!(group: grp) else raise "unsupported action for missing devices: '#{missing_devices}'" end save_config lxc_config.configure configure_bashrc end |
#chown(user) ⇒ Object
301 302 303 304 305 306 |
# File 'lib/osctld/container.rb', line 301 def chown(user) self.user = user save_config lxc_config.configure configure_bashrc end |
#clear_start_menu ⇒ Object
654 655 656 657 |
# File 'lib/osctld/container.rb', line 654 def = .unlink if end |
#clone_from(_ct, id, opts = {}) ⇒ Object (protected)
Change the container so that it becomes a clone of ‘ct` with a different id
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 |
# File 'lib/osctld/container.rb', line 1023 def clone_from(_ct, id, opts = {}) init_lock init_manipulable @id = id @pool = opts[:pool] if opts[:pool] @user = opts[:user] if opts[:user] @group = opts[:group] if opts[:group] @state = :staged @send_log = nil @local_transfer_log = nil @dataset = if opts[:dataset] OsCtl::Lib::Zfs::Dataset.new( opts[:dataset], base: opts[:dataset] ) else Container.default_dataset(@pool, @id) end @apparmor = @apparmor.dup(self) @autostart &&= @autostart.dup(self) @cgparams = cgparams.dup(self) @prlimits = prlimits.dup(self) @mounts = mounts.dup(self) @start_menu &&= @start_menu.dup(self) @impermanence &&= @impermanence.dup @lxc_config = lxc_config.dup(self) @raw_configs = raw_configs.dup @attrs = attrs.dup @run_conf = nil @next_run_conf = nil @past_run_conf = nil @devices = devices.dup(self) devices.init if opts[:network_interfaces] @netifs = netifs.dup(self) netifs.each(&:setup) else @netifs = NetInterface::Manager.new(self) end @hints = hints.dup(self) end |
#close_local_transfer_log(save: true) ⇒ Object
718 719 720 721 722 723 724 |
# File 'lib/osctld/container.rb', line 718 def close_local_transfer_log(save: true) exclusively do local_transfer_log.close self.local_transfer_log = nil save_config if save end end |
#close_send_log(save: true) ⇒ Object
703 704 705 706 707 708 709 |
# File 'lib/osctld/container.rb', line 703 def close_send_log(save: true) exclusively do send_log.close self.send_log = nil save_config if save end end |
#config_path ⇒ Object
429 430 431 |
# File 'lib/osctld/container.rb', line 429 def config_path inclusively { File.join(pool.conf_path, 'ct', "#{id}.yml") } end |
#configure(distribution, version, arch) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/osctld/container.rb', line 104 def configure(distribution, version, arch) exclusively do @distribution = distribution @version = version @arch = arch @netifs = NetInterface::Manager.new(self) @nesting = false @seccomp_profile = default_seccomp_profile @cgparams = CGroup::ContainerParams.new(self) @devices = Devices::Manager.new_for(self) @prlimits = PrLimits::Manager.default(self) @mounts = Mount::Manager.new(self) @run_conf ||= new_run_conf devices.init save_config end end |
#configure_bashrc ⇒ Object
682 683 684 685 686 687 688 689 690 691 692 693 694 |
# File 'lib/osctld/container.rb', line 682 def configure_bashrc ErbTemplate.render_to('ct/bashrc', { ct: self, override: %w[ attach cgroup console device execute freeze info ls monitor stop top unfreeze wait ], disable: %w[ autostart checkpoint clone copy create destroy snapshot start-ephemeral unshare ] }, File.join(lxc_dir, '.bashrc')) end |
#current_state ⇒ Symbol
Fetch current container state by forking into it
352 353 354 355 356 |
# File 'lib/osctld/container.rb', line 352 def current_state self.state = ContainerControl::Commands::State.run!(self).state rescue ContainerControl::Error self.state = :error end |
#datasets ⇒ Array<OsCtl::Lib::Zfs::Dataset>
Return a list of all container datasets
455 456 457 458 |
# File 'lib/osctld/container.rb', line 455 def datasets ds = inclusively { dataset } [ds] + ds.descendants end |
#default_init_cmd ⇒ Object (protected)
1075 1076 1077 |
# File 'lib/osctld/container.rb', line 1075 def default_init_cmd ['/sbin/init'] end |
#default_seccomp_profile ⇒ Object (protected)
1071 1072 1073 |
# File 'lib/osctld/container.rb', line 1071 def default_seccomp_profile '/etc/lxc/config/common.seccomp' end |
#dir ⇒ Object
409 410 411 |
# File 'lib/osctld/container.rb', line 409 def dir dataset.mountpoint end |
#dump_config ⇒ Object
Dump to config
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 |
# File 'lib/osctld/container.rb', line 791 def dump_config inclusively do data = { 'user' => user.name, 'group' => group.name, 'dataset' => dataset.name, 'map_mode' => map_mode, 'distribution' => distribution, 'version' => version, 'arch' => arch, 'vendor' => vendor, 'variant' => variant, 'net_interfaces' => netifs.dump, 'cgparams' => cgparams.dump, 'devices' => devices.dump, 'prlimits' => prlimits.dump, 'mounts' => mounts.dump, 'autostart' => autostart && autostart.dump, 'ephemeral' => ephemeral, 'hostname' => hostname && hostname.to_s, 'dns_resolvers' => dns_resolvers, 'nesting' => nesting, 'seccomp_profile' => if seccomp_profile == default_seccomp_profile nil else seccomp_profile end, 'cpu_package' => cpu_package, 'init_cmd' => init_cmd, 'start_menu' => && .dump, 'impermanence' => impermanence && impermanence.dump, 'raw' => raw_configs.dump, 'attrs' => attrs.dump, 'hints' => hints.dump } data['state'] = 'staged' if state == :staged data['send_log'] = send_log.dump if send_log data['local_transfer_log'] = local_transfer_log.dump if local_transfer_log data end end |
#dup(id, opts = {}) ⇒ Object
Duplicate the container with a different ID
The returned container has ‘state` set to `:staged` and its assets will not exist, so the caller has to build the container and call `ct.state = :complete` for the container to become usable.
210 211 212 213 214 |
# File 'lib/osctld/container.rb', line 210 def dup(id, opts = {}) ct = clone ct.send(:clone_from, self, id, opts) ct end |
#each_dataset {|ds| ... } ⇒ Object
Iterate over all container datasets
462 463 464 |
# File 'lib/osctld/container.rb', line 462 def each_dataset(&) datasets.each(&) end |
#ensure_run_conf ⇒ Container::RunConfiguration
Call #init_run_conf unless #run_conf is already set
259 260 261 262 263 264 |
# File 'lib/osctld/container.rb', line 259 def ensure_run_conf exclusively do init_run_conf if @run_conf.nil? run_conf end end |
#entry_cgroup_path ⇒ Object
478 479 480 |
# File 'lib/osctld/container.rb', line 478 def entry_cgroup_path File.join(cgroup_path, "lxc.monitor.#{id}") end |
#export ⇒ Object
Export to clients
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 |
# File 'lib/osctld/container.rb', line 742 def export inclusively do { pool: pool.name, id:, user: user.name, group: group.name, uid_map: user.uid_map.map(&:to_h), gid_map: user.gid_map.map(&:to_h), map_mode: map_mode, dataset: dataset.name, rootfs:, boot_dataset: run_conf ? run_conf.dataset.name : dataset.name, boot_rootfs: run_conf ? run_conf.rootfs : rootfs, lxc_path: lxc_home, lxc_dir:, group_path: cgroup_path, distribution: run_conf ? run_conf.distribution : distribution, version: run_conf ? run_conf.version : version, arch: run_conf ? run_conf.arch : arch, vendor: run_conf ? run_conf.vendor : vendor, variant: run_conf ? run_conf.variant : variant, state:, init_pid:, autostart: autostart ? true : false, autostart_priority: autostart && autostart.priority, autostart_delay: autostart && autostart.delay, ephemeral:, hostname:, dns_resolvers:, nesting:, seccomp_profile:, init_cmd: format_user_init_cmd, cpu_package_inuse: run_conf ? run_conf.cpu_package : nil, cpu_package_set: cpu_package, cpu_limit: find_cpu_limit(parents: false), memory_limit: find_memory_limit(parents: false), swap_limit: find_swap_limit(parents: false), start_menu: ? true : false, start_menu_timeout: && .timeout, impermanence: impermanence ? true : false, impermanence_zfs_properties: impermanence&.zfs_properties, raw_lxc: raw_configs.lxc, log_file: log_path }.merge!(attrs.export) end end |
#find_cpu_limit(parents: true) ⇒ Integer?
Returns CPU limit in percent (100 % for one CPU).
517 518 519 520 521 522 523 524 525 526 527 |
# File 'lib/osctld/container.rb', line 517 def find_cpu_limit(parents: true) limit = cgparams.find_cpu_limit if limit return limit elsif !parents return end group.find_cpu_limit(parents:) end |
#find_memory_limit(parents: true) ⇒ Integer?
Returns memory limit in bytes.
491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/osctld/container.rb', line 491 def find_memory_limit(parents: true) limit = cgparams.find_memory_limit if limit return limit elsif !parents return end group.find_memory_limit(parents:) end |
#find_swap_limit(parents: true) ⇒ Integer?
Returns swap limit in bytes.
504 505 506 507 508 509 510 511 512 513 514 |
# File 'lib/osctld/container.rb', line 504 def find_swap_limit(parents: true) limit = cgparams.find_swap_limit if limit return limit elsif !parents return end group.find_swap_limit(parents:) end |
#forget_past_run_conf ⇒ Object
231 232 233 |
# File 'lib/osctld/container.rb', line 231 def forget_past_run_conf exclusively { @past_run_conf = nil } end |
#format_exec_init_cmd ⇒ Object
870 871 872 873 874 875 876 877 878 879 |
# File 'lib/osctld/container.rb', line 870 def format_exec_init_cmd cmd = init_cmd || default_init_cmd = if .init_cmd(cmd) else cmd end.join(' ') end |
#format_user_init_cmd ⇒ Object
866 867 868 |
# File 'lib/osctld/container.rb', line 866 def format_user_init_cmd (init_cmd || default_init_cmd).join(' ') end |
#fresh_state ⇒ Symbol
Fetch current state if the state is not known, otherwise return the known state
360 361 362 363 364 365 366 |
# File 'lib/osctld/container.rb', line 360 def fresh_state if state == :unknown current_state else state end end |
#get_past_run_conf ⇒ Container::RunConfiguration?
227 228 229 |
# File 'lib/osctld/container.rb', line 227 def get_past_run_conf inclusively { @past_run_conf } end |
#get_run_conf ⇒ Container::RunConfiguration
222 223 224 |
# File 'lib/osctld/container.rb', line 222 def get_run_conf run_conf || new_run_conf end |
#gid_map ⇒ Object
441 442 443 |
# File 'lib/osctld/container.rb', line 441 def gid_map user.gid_map end |
#ident ⇒ Object
100 101 102 |
# File 'lib/osctld/container.rb', line 100 def ident inclusively { "#{pool.name}:#{id}" } end |
#init_pid ⇒ Object
376 377 378 379 380 |
# File 'lib/osctld/container.rb', line 376 def init_pid inclusively do @run_conf ? run_conf.init_pid : nil end end |
#init_run_conf ⇒ Object
This must be called on container start
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/osctld/container.rb', line 241 def init_run_conf exclusively do if @next_run_conf @run_conf = @next_run_conf @next_run_conf = nil else @run_conf = new_run_conf end @run_conf.save end # Generate LXC configs for current time namespace offsets reconfigure end |
#load_config_file(path = nil) ⇒ Object (protected)
917 918 919 920 921 922 923 |
# File 'lib/osctld/container.rb', line 917 def load_config_file(path = nil, **) cfg = parse_yaml do OsCtl::Lib::ConfigFile.load_yaml_file(path || config_path) end load_config_hash(cfg, **) end |
#load_config_hash(cfg, init_devices: true, dataset_cache: nil) ⇒ Object (protected)
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
# File 'lib/osctld/container.rb', line 936 def load_config_hash(cfg, init_devices: true, dataset_cache: nil) cfg = Container::Adaptor.adapt(self, cfg) exclusively do @state = cfg['state'].to_sym if cfg['state'] @user ||= DB::Users.find(cfg['user'], pool) || (raise ConfigError, "container #{id}: user '#{cfg['user']}' not found") @group ||= DB::Groups.find(cfg['group'], pool) || (raise ConfigError, "container #{id}: group '#{cfg['group']}' not found") @dataset ||= if cfg['dataset'] OsCtl::Lib::Zfs::Dataset.new( cfg['dataset'], base: cfg['dataset'], cache: dataset_cache ) else Container.default_dataset( pool, id, dataset_cache: ) end @map_mode ||= cfg.fetch('map_mode', 'zfs') @distribution = cfg['distribution'] @version = cfg['version'] @arch = cfg['arch'] @vendor = cfg.fetch('vendor', 'default') @variant = cfg.fetch('variant', 'default') @autostart = cfg['autostart'] && AutoStart::Config.load(self, cfg['autostart']) @ephemeral = cfg['ephemeral'] @hostname = cfg['hostname'] && OsCtl::Lib::Hostname.new(cfg['hostname']) @dns_resolvers = cfg['dns_resolvers'] @nesting = cfg['nesting'] || false @cpu_package = cfg.fetch('cpu_package', 'auto') @seccomp_profile = cfg['seccomp_profile'] || default_seccomp_profile @init_cmd = cfg['init_cmd'] @start_menu = if !cfg.has_key?('start_menu') || cfg['start_menu'] Container::StartMenu.load(self, cfg['start_menu'] || {}) end @impermanence = if cfg['impermanence'] Container::Impermanence.load(cfg['impermanence']) end @run_conf = Container::RunConfiguration.load(self) if cfg['send_log'] @send_log = SendReceive::Log.load(cfg['send_log']) SendReceive::Tokens.register(@send_log.token) end if cfg['local_transfer_log'] @local_transfer_log = LocalTransfer::Log.load(cfg['local_transfer_log']) end @cgparams = CGroup::ContainerParams.load(self, cfg['cgparams']) @prlimits = PrLimits::Manager.load(self, cfg['prlimits'] || {}) @raw_configs = Container::RawConfigs.new(cfg['raw'] || {}) @attrs = Attributes.load(cfg['attrs'] || {}) # It's necessary to load devices _before_ netifs. The device manager needs # to create cgroups first, in order for echo a > devices.deny to work. # If the container has a veth interface, the setup code switches to the # container's user, which creates cgroups in all subsystems. Devices then # can't be initialized properly. @devices = Devices::Manager.load(self, cfg['devices'] || []) @devices.init if init_devices @netifs = NetInterface::Manager.load(self, cfg['net_interfaces'] || []) @mounts = Mount::Manager.load(self, cfg['mounts'] || []) @hints = Container::Hints.load(self, cfg['hints'] || {}) end end |
#load_config_string(str) ⇒ Object (protected)
925 926 927 928 |
# File 'lib/osctld/container.rb', line 925 def load_config_string(str, **) cfg = parse_yaml { OsCtl::Lib::ConfigFile.load_yaml(str) } load_config_hash(cfg, **) end |
#log_path ⇒ Object
896 897 898 |
# File 'lib/osctld/container.rb', line 896 def log_path inclusively { File.join(pool.log_path, 'ct', "#{id}.log") } end |
#log_type ⇒ Object
900 901 902 |
# File 'lib/osctld/container.rb', line 900 def log_type inclusively { "ct=#{pool.name}:#{id}" } end |
#lxc_dir(user: nil, group: nil) ⇒ Object
417 418 419 |
# File 'lib/osctld/container.rb', line 417 def lxc_dir(user: nil, group: nil) inclusively { File.join(lxc_home(user:, group:), id) } end |
#lxc_home(user: nil, group: nil) ⇒ Object
413 414 415 |
# File 'lib/osctld/container.rb', line 413 def lxc_home(user: nil, group: nil) inclusively { (group || self.group).userdir(user || self.user) } end |
#manipulation_resource ⇒ Object
904 905 906 |
# File 'lib/osctld/container.rb', line 904 def manipulation_resource ['container', ident] end |
#mount(force: false) ⇒ Object
Mount the container’s dataset
269 270 271 272 273 274 |
# File 'lib/osctld/container.rb', line 269 def mount(force: false) return if !force && mounted dataset.mount(recursive: true) self.mounted = true end |
#mounted?(force: false) ⇒ Boolean
Check if the container’s dataset is mounted
287 288 289 290 291 292 293 |
# File 'lib/osctld/container.rb', line 287 def mounted?(force: false) if force || mounted.nil? self.mounted = dataset.mounted?(recursive: true) else mounted end end |
#new_run_conf ⇒ Container::RunConfiguration
217 218 219 |
# File 'lib/osctld/container.rb', line 217 def new_run_conf Container::RunConfiguration.new(self, load_conf: false) end |
#open_local_transfer_log(role, opts = {}) ⇒ Object
711 712 713 714 715 716 |
# File 'lib/osctld/container.rb', line 711 def open_local_transfer_log(role, opts = {}) exclusively do self.local_transfer_log = LocalTransfer::Log.new(role:, opts:) save_config end end |
#open_send_log(role, token, opts = {}) ⇒ Object
696 697 698 699 700 701 |
# File 'lib/osctld/container.rb', line 696 def open_send_log(role, token, opts = {}) exclusively do self.send_log = SendReceive::Log.new(role:, token:, opts:) save_config end end |
#parse_yaml ⇒ Object (protected)
930 931 932 933 934 |
# File 'lib/osctld/container.rb', line 930 def parse_yaml yield rescue Psych::Exception => e raise ConfigError.new("Unable to load config of container #{id}", e) end |
#patch_config(new_config) ⇒ Object
Update keys/values from ‘new_config` in the container’s config
857 858 859 860 861 862 863 864 |
# File 'lib/osctld/container.rb', line 857 def patch_config(new_config) exclusively do tmp = dump_config tmp.update(new_config) load_config_hash(tmp) save_config end end |
#read_hostname ⇒ String?
Read hostname from a running container
661 662 663 664 665 666 667 668 669 670 |
# File 'lib/osctld/container.rb', line 661 def read_hostname return nil unless running? begin ContainerControl::Commands::GetHostname.run!(self) rescue ContainerControl::Error => e log(:warn, "Unable to read container hostname: #{e.}") nil end end |
#reconfigure ⇒ Object
Regenerate LXC config
678 679 680 |
# File 'lib/osctld/container.rb', line 678 def reconfigure lxc_config.configure end |
#reload_config ⇒ Object
845 846 847 |
# File 'lib/osctld/container.rb', line 845 def reload_config load_config_file end |
#replace_config(config) ⇒ Object
850 851 852 853 |
# File 'lib/osctld/container.rb', line 850 def replace_config(config) load_config_string(config) save_config end |
#root_host_gid ⇒ Object
449 450 451 |
# File 'lib/osctld/container.rb', line 449 def root_host_gid user.gid_map.ns_to_host(0) end |
#root_host_uid ⇒ Object
445 446 447 |
# File 'lib/osctld/container.rb', line 445 def root_host_uid user.uid_map.ns_to_host(0) end |
#rootfs ⇒ Object
421 422 423 424 425 426 427 |
# File 'lib/osctld/container.rb', line 421 def rootfs File.join(dir, 'private') rescue SystemCommandFailed # Dataset for staged containers does not have to exist yet, relevant # primarily for ct show/list nil end |
#running? ⇒ Boolean
368 369 370 |
# File 'lib/osctld/container.rb', line 368 def running? state == :running end |
#save_config ⇒ Object
835 836 837 838 839 840 841 842 843 |
# File 'lib/osctld/container.rb', line 835 def save_config data = dump_config regenerate_file(config_path, 0o400) do |f| f.write(OsCtl::Lib::ConfigFile.dump_yaml(data)) end File.chown(0, 0, config_path) end |
#set(opts) ⇒ Object
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 |
# File 'lib/osctld/container.rb', line 529 def set(opts) opts.each do |k, v| case k when :autostart self.autostart = AutoStart::Config.new(self, v[:priority], v[:delay]) when :ephemeral self.ephemeral = true when :hostname original = nil exclusively do original = @hostname @hostname = OsCtl::Lib::Hostname.new(v) end DistConfig.run(get_run_conf, :set_hostname, original:) when :dns_resolvers self.dns_resolvers = v DistConfig.run(get_run_conf, :dns_resolvers) when :nesting self.nesting = true when :distribution exclusively do @distribution = v[:name] @version = v[:version] @arch = v[:arch] if v[:arch] @vendor = v[:vendor] @variant = v[:variant] end if (rc = run_conf) rc.set_distribution( distribution:, version:, arch:, vendor:, variant: ) end when :cpu_package self.cpu_package = v when :seccomp_profile self.seccomp_profile = v when :init_cmd self.init_cmd = v when :start_menu self. = Container::StartMenu.new(self, v[:timeout]) when :impermanence self.impermanence = Container::Impermanence.new(v[:zfs_properties].transform_keys(&:to_s)) when :raw_lxc raw_configs.lxc = v when :attrs attrs.update(v) end end save_config lxc_config.configure_base end |
#set_next_run_conf(next_run_conf) ⇒ Object
236 237 238 |
# File 'lib/osctld/container.rb', line 236 def set_next_run_conf(next_run_conf) exclusively { @next_run_conf = next_run_conf } end |
#setup_start_menu ⇒ Object
649 650 651 652 |
# File 'lib/osctld/container.rb', line 649 def = .deploy if end |
#starting ⇒ Object
382 383 384 385 386 387 388 389 |
# File 'lib/osctld/container.rb', line 382 def starting exclusively do # Normally {#init_run_conf} is called from {Commands::Container::Start}, # but in case the lxc-start was invoked manually outside of osctld, # initiate the run conf if needed. ensure_run_conf end end |
#stopped ⇒ Object
391 392 393 394 395 396 397 398 399 |
# File 'lib/osctld/container.rb', line 391 def stopped exclusively do if run_conf run_conf.destroy @past_run_conf = @run_conf @run_conf = nil end end end |
#syslogns_tag ⇒ Object
881 882 883 884 885 886 887 888 889 890 891 892 893 894 |
# File 'lib/osctld/container.rb', line 881 def syslogns_tag max_size = OsCtl::Lib::Sys::SYSLOGNS_MAX_TAG_BYTESIZE tag = if id.bytesize >= max_size - 1 # -1 for colon used as a separator id[0..(max_size - 1)] else v = ident v = v[1..] while v.bytesize > max_size v end tag.rjust(max_size) end |
#transfer_in_progress? ⇒ Boolean
730 731 732 |
# File 'lib/osctld/container.rb', line 730 def transfer_in_progress? inclusively { !!send_log || !!local_transfer_log } end |
#transfer_log ⇒ Object
726 727 728 |
# File 'lib/osctld/container.rb', line 726 def transfer_log inclusively { send_log || local_transfer_log } end |
#uid_map ⇒ Object
437 438 439 |
# File 'lib/osctld/container.rb', line 437 def uid_map user.uid_map end |
#unmount(force: false) ⇒ Object
Unmount the container’s dataset
277 278 279 280 281 282 |
# File 'lib/osctld/container.rb', line 277 def unmount(force: false) return if !force && !mounted dataset.unmount(recursive: true) self.mounted = false end |
#unregister ⇒ Object
Unregister the container from internal uses in osctld, e.g. on pool export
735 736 737 738 739 |
# File 'lib/osctld/container.rb', line 735 def unregister exclusively do SendReceive::Tokens.free(send_log.token) if send_log end end |
#unset(opts) ⇒ Object
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 |
# File 'lib/osctld/container.rb', line 601 def unset(opts) opts.each do |k, v| case k when :autostart self.autostart = false pool.autostart_plan.stop_ct(self) when :ephemeral self.ephemeral = false when :hostname self.hostname = nil DistConfig.run(get_run_conf, :unset_etc_hosts) when :dns_resolvers self.dns_resolvers = nil when :nesting self.nesting = false when :cpu_package self.cpu_package = 'auto' when :seccomp_profile self.seccomp_profile = default_seccomp_profile when :init_cmd self.init_cmd = nil when :start_menu self. = nil when :impermanence self.impermanence = nil when :raw_lxc raw_configs.lxc = nil when :attrs v.each { |attr| attrs.unset(attr) } end end save_config lxc_config.configure_base end |
#update_hints ⇒ Object
672 673 674 675 |
# File 'lib/osctld/container.rb', line 672 def update_hints hints.account_cpu_use save_config end |
#user_hook_script_dir ⇒ Object
433 434 435 |
# File 'lib/osctld/container.rb', line 433 def user_hook_script_dir inclusively { File.join(pool.root_user_hook_script_dir, 'ct', id) } end |
#wrapper_cgroup_path ⇒ Object
474 475 476 |
# File 'lib/osctld/container.rb', line 474 def wrapper_cgroup_path File.join(base_cgroup_path, 'wrapper') end |