Class: OsCtld::Commands::Container::Start
- Includes:
- OsCtl::Lib::Utils::Log, OsCtl::Lib::Utils::System, Utils::SwitchUser
- Defined in:
- lib/osctld/commands/container/start.rb
Instance Attribute Summary
Attributes inherited from Base
#client, #client_handler, #id, #opts
Instance Method Summary collapse
- #execute(ct) ⇒ Object
- #find ⇒ Object
- #start_now(ct) ⇒ Object protected
- #start_queued(ct) ⇒ Object protected
-
#wait_for_ct(event_queue, ct) ⇒ Object
protected
Wait for the container to start or fail.
Methods included from Utils::SwitchUser
#ct_attach, #ct_control, #ct_exec, #ct_runscript, #ct_syscmd, #init_script, #unlink_file
Methods inherited from Logged
Methods inherited from Base
#base_execute, #call_cmd, #call_cmd!, cmd, #error, #error!, 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
#execute(ct) ⇒ Object
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/osctld/commands/container/start.rb', line 16 def execute(ct) return start_queued(ct) if opts[:queue] event_queue = nil manipulate(ct) do event_queue = Eventd.subscribe ret = start_now(ct) # Exit if we don't need to wait if ret != :wait return ret elsif opts[:wait] === false return ok end # Wait for the container to enter state `running` progress('Waiting for the container to start') started = wait_for_ct(event_queue, ct) Eventd.unsubscribe(event_queue) if started # Access `/proc/stat` and `/proc/loadavg` within the container, so that # LXCFS starts tracking it immediately. ct_syscmd(ct, 'cat /proc/stat', valid_rcs: :all) ct_syscmd(ct, 'cat /proc/loadavg', valid_rcs: :all) ok else error('container failed to start') end end end |
#find ⇒ Object
11 12 13 14 |
# File 'lib/osctld/commands/container/start.rb', line 11 def find ct = DB::Containers.find(opts[:id], opts[:pool]) ct || error!('container not found') end |
#start_now(ct) ⇒ Object (protected)
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 111 112 113 114 115 116 117 118 119 120 121 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 |
# File 'lib/osctld/commands/container/start.rb', line 80 def start_now(ct) error!('start not available') unless ct.can_start? return ok if ct.running? && !opts[:force] # Remove any left-over temporary mounts ct.mounts.prune # Reset log file File.open(ct.log_path, 'w').close File.chmod(0660, ct.log_path) File.chown(0, ct.user.ugid, ct.log_path) # Console dir console_dir = File.join(ct.pool.console_dir, ct.id) Dir.mkdir(console_dir) unless Dir.exist?(console_dir) File.chown(ct.user.ugid, 0, console_dir) File.chmod(0700, console_dir) # Remove stray sockets sock_path = Console.socket_path(ct) if File.exist?(sock_path) log(:info, ct, "Removing leftover tty0 socket at #{sock_path}") begin File.unlink(sock_path) rescue Errno::ENOENT # Continue if the socket was already deleted end end cmd = [ OsCtld.bin('osctld-ct-wrapper'), "#{ct.pool.name}:#{ct.id}", Console.socket_path(ct), 'lxc-start', '-P', ct.lxc_home, '-n', ct.id, '-o', ct.log_path, '-l', opts[:debug] ? 'DEBUG' : 'ERROR', '-F' ] r, w = IO.pipe progress('Starting container') pid = SwitchUser.fork_and_switch_to( ct.user.sysusername, ct.user.ugid, ct.user.homedir, ct.cgroup_path, prlimits: ct.prlimits.export, ) do r.close wrapper_pid = Process.spawn( *cmd, pgroup: true, in: :close, out: :close, err: :close ) w.puts(wrapper_pid.to_s) end w.close wrapper_pid = r.readline.strip.to_i r.close progress('Connecting console') begin Console.connect_tty0(ct, wrapper_pid) rescue Errno::ENOENT log(:warn, ct, "Unable to connect to tty0") end Process.wait(pid) :wait end |
#start_queued(ct) ⇒ Object (protected)
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 |
# File 'lib/osctld/commands/container/start.rb', line 53 def start_queued(ct) progress('Joining the queue') if opts[:wait] === false ct.pool.autostart_plan.enqueue( ct, priority: opts[:priority], start_opts: opts, ) return ok end ret = ct.pool.autostart_plan.start_ct( ct, priority: opts[:priority], start_opts: opts, client_handler: client_handler, ) if ret.nil? ok('Timed out') else ret end end |
#wait_for_ct(event_queue, ct) ⇒ Object (protected)
Wait for the container to start or fail
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 |
# File 'lib/osctld/commands/container/start.rb', line 159 def wait_for_ct(event_queue, ct) # Sequence of events that lead to the container being started. # We're accepting even `stopping` and `stopped`, since when the container # is being restarted, these events may be received and should not cause # this method to exit. sequence = %i(stopping stopped starting running) last_i = nil loop do event = event_queue.pop(timeout: opts[:wait] || 60) return false if event.nil? # Ignore irrelevant events next if event.type != :state \ || event.opts[:pool] != ct.pool.name \ || event.opts[:id] != ct.id state = event.opts[:state] cur_i = sequence.index(state) return false if cur_i.nil? || (last_i && cur_i < last_i) return true if state == sequence.last last_i = cur_i end end |