Module: OsCtld::ContainerControl::Utils::Runscript::Runner

Included in:
Commands::Exec::Runner, Commands::Runscript::Runner
Defined in:
lib/osctld/container_control/utils/runscript.rb

Instance Method Summary collapse

Instance Method Details

#runscript_run(opts) ⇒ Object

Execute script in a stopped container

Parameters:

  • opts (Hash)

Options Hash (opts):

  • :script (String)

    path to the script relative to the rootfs

  • :stdin (IO)
  • :stdout (IO)
  • :stderr (IO)
  • :close_fds (Array<IO>)
  • :wait (Boolean)


44
45
46
47
48
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
# File 'lib/osctld/container_control/utils/runscript.rb', line 44

def runscript_run(opts)
  pid = Process.fork do
    cur_stdin = opts.fetch(:stdin, stdin)
    cur_stdout = opts.fetch(:stdout, stdout)
    cur_stderr = opts.fetch(:stderr, stderr)

    if cur_stdin
      $stdin.reopen(cur_stdin)
    else
      $stdin.close
    end

    $stdout.reopen(cur_stdout)
    $stderr.reopen(cur_stderr) if cur_stderr

    opts[:close_fds] && opts[:close_fds].each(&:close)

    setup_exec_run_env

    cmd = [
      'lxc-execute',
      '-P', lxc_home,
      '-n', ctid,
      '-o', log_file,
      '-s', "lxc.environment=PATH=#{system_path.join(':')}",
      '-s', 'lxc.environment=HOME=/root',
      '-s', 'lxc.environment=USER=root',
      '--',
      opts[:script]
    ]

    # opts[:cmd] can contain an arbitrary command with multiple arguments
    # and quotes, so the mapping to process arguments is not clear. We use
    # the shell to handle this.
    Process.exec("exec #{cmd.join(' ')}")
  end

  if opts[:wait] === false
    pid
  else
    _, status = Process.wait2(pid)
    ok(status.exitstatus)
  end
end

#with_configured_network(opts) ⇒ Object

Start container with lxc-init, configure network and yield

opts has to contain path to a script that will be executed by lxc-init. The purpose of this script is to keep the container running while the network is being configured and the user command is executed. The script has to write ‘readyn` to standard output, then block on read from standard input and exit.

Parameters:

  • opts (Hash)

Options Hash (opts):

  • :init_script (String)

    path to the script used to control the container

  • :net_config (Hash)


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
# File 'lib/osctld/container_control/utils/runscript.rb', line 101

def with_configured_network(opts)
  ret = nil

  # Pipes for communicating with opts[:init_script]
  in_r, in_w = IO.pipe
  out_r, out_w = IO.pipe

  # Start the container with lxc-init
  init_pid = runscript_run(
    id: ctid,
    script: opts[:init_script],
    stdin: in_r,
    stdout: out_w,
    stderr: nil,
    close_fds: [in_w, out_r],
    wait: false
  )

  in_r.close
  out_w.close

  # Wait for the container to be started
  if out_r.readline.strip == 'ready'
    # Configure network
    pid = lxc_ct.attach do
      setup_exec_env
      ENV['HOME'] = '/root'
      ENV['USER'] = 'root'
      NetConfig.import(opts[:net_config]).setup
    end

    Process.wait2(pid)

    # Execute user command
    ret = yield
  end

  # Closing in_w will bring down opts[:init_script] and stop the container
  in_w.close
  out_r.close

  _, status = Process.wait2(init_pid)
  ret || ok(status.exitstatus)
end