Class: OsCtl::Image::Operations::Builder::ControlledExec

Inherits:
OsCtl::Image::Operations::Base show all
Includes:
Lib::Utils::Log, Lib::Utils::System
Defined in:
lib/osctl/image/operations/builder/controlled_exec.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from OsCtl::Image::Operations::Base

run

Constructor Details

#initialize(builder, command, id: nil, client: nil, env: {}) ⇒ ControlledExec

Returns a new instance of ControlledExec.

Parameters:

  • builder (Builder)
  • command (Array<String>)
  • id (nil, String) (defaults to: nil)

    optional run identifier

  • client (nil, OsCtldClient) (defaults to: nil)
  • env (Hash<String, String>) (defaults to: {})


22
23
24
25
26
27
28
29
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 22

def initialize(builder, command, id: nil, client: nil, env: {})
  super()
  @builder = builder
  @command = command
  @id = id || SecureRandom.hex(10)
  @client = client || OsCtldClient.new
  @env = env
end

Instance Attribute Details

#builderBuilder (readonly)

Returns:



12
13
14
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 12

def builder
  @builder
end

#clientObject (readonly, protected)

Returns the value of attribute client.



48
49
50
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 48

def client
  @client
end

#commandArray<String> (readonly)

Returns:

  • (Array<String>)


15
16
17
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 15

def command
  @command
end

#envObject (readonly, protected)

Returns the value of attribute env.



48
49
50
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 48

def env
  @env
end

#idObject (readonly, protected)

Returns the value of attribute id.



48
49
50
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 48

def id
  @id
end

Instance Method Details

#cgroup_nameObject (protected)



100
101
102
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 100

def cgroup_name
  "osctl-image.exec.#{id}"
end

#clear_cgroupObject (protected)



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 64

def clear_cgroup
  cgroup = outer_cgroup_path

  unless Dir.exist?(cgroup)
    log(:info, 'cgroup not found, nothing to kill')
    return
  end

  log(:info, "clearing cgroup #{cgroup}")

  if kill_all(cgroup, 'TERM')
    sleep(5)
    kill_all(cgroup, 'KILL')
  end

  Dir.rmdir(cgroup)
rescue Errno::ENOENT
  # ignore
end

#executeInteger

Returns exit status.

Returns:

  • (Integer)

    exit status



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 32

def execute
  begin
    rc = Operations::Builder::RunscriptFromString.run(
      builder,
      start_script,
      client:
    )
  ensure
    clear_cgroup
  end

  rc || 1
end

#inner_cgroup_pathObject (protected)



104
105
106
107
108
109
110
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 104

def inner_cgroup_path
  if OsCtl::Lib::CGroup.v2?
    File.join('/sys/fs/cgroup', cgroup_name)
  else
    File.join('/sys/fs/cgroup/systemd', cgroup_name)
  end
end

#kill_all(cgroup, signal) ⇒ Object (protected)



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 84

def kill_all(cgroup, signal)
  killed = false

  File.open(File.join(cgroup, 'cgroup.procs'), 'r') do |f|
    f.each_line do |line|
      pid = line.strip.to_i

      log(:info, "kill -SIG#{signal} #{pid}")
      Process.kill(signal, pid)
      killed = true
    end
  end

  killed
end

#outer_cgroup_pathObject (protected)



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 112

def outer_cgroup_path
  if OsCtl::Lib::CGroup.v2?
    File.join(
      '/sys/fs/cgroup',
      builder.attrs[:group_path],
      "lxc.payload.#{builder.ctid}",
      cgroup_name
    )
  else
    File.join(
      '/sys/fs/cgroup/systemd',
      builder.attrs[:group_path],
      "lxc.payload.#{builder.ctid}",
      cgroup_name
    )
  end
end

#start_scriptObject (protected)



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/osctl/image/operations/builder/controlled_exec.rb', line 50

def start_script
  exec_cmd = ['env']
  exec_cmd.concat(env.map { |k, v| "#{k}=#{v}" }) unless env.empty?
  exec_cmd.concat(command)

  <<~EOF
    #!/bin/sh
    cgroup="#{inner_cgroup_path}"
    mkdir "$cgroup"
    echo $$ >> "$cgroup/cgroup.procs"
    exec #{Shellwords.join(exec_cmd)}
  EOF
end