Class: OsCtld::Monitor::Process

Inherits:
Object
  • Object
show all
Includes:
OsCtl::Lib::Utils::Log
Defined in:
lib/osctld/monitor/process.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pool, user, group, stdout) ⇒ Process

Returns a new instance of Process.



57
58
59
60
61
62
63
# File 'lib/osctld/monitor/process.rb', line 57

def initialize(pool, user, group, stdout)
  @pool = pool
  @user = user
  @group = group
  @stdout = stdout
  @last_line = nil
end

Class Method Details

.cgroup_path(ct) ⇒ Object



53
54
55
# File 'lib/osctld/monitor/process.rb', line 53

def self.cgroup_path(ct)
  File.join(ct.group.full_cgroup_path(ct.user), 'monitor')
end

.spawn(ct) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/osctld/monitor/process.rb', line 7

def self.spawn(ct)
  cg_path = cgroup_path(ct)
  out_r, out_w = IO.pipe

  CGroup.mkpath_all(cg_path.split('/'))

  pid = Process.fork do
    $stdout.reopen(out_w)
    out_r.close

    SwitchUser.switch_to(
      ct.user.sysusername,
      ct.user.ugid,
      ct.user.homedir,
      cg_path
    )

    Process.exec('lxc-monitor', '-P', ct.lxc_home, '-n', '.*')
  end

  out_w.close
  [pid, out_r]
end

.stop_monitord(ct) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/osctld/monitor/process.rb', line 31

def self.stop_monitord(ct)
  pid = Process.fork do
    SwitchUser.switch_to(
      ct.user.sysusername,
      ct.user.ugid,
      ct.user.homedir,
      cgroup_path(ct)
    )

    Process.exec('lxc-monitor', '-P', ct.lxc_home, '--quit')
  end

  Process.wait(pid)

  if $?.exitstatus == 0
    log(:info, :monitor, 'Stopped lxc-monitord')

  else
    log(:info, :monitor, 'Failed to stop lxc-monitord')
  end
end

Instance Method Details

#monitorObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/osctld/monitor/process.rb', line 65

def monitor
  # First, get container's current state

  until @stdout.eof?
    line = @stdout.readline
    next if line == @last_line

    @last_line = line

    state = parse(line)
    next unless state

    update_state(state)
  end

  true
rescue IOError
  log(:info, :monitor, "Monitoring of #{@pool.name}:#{@user.name}:#{@group.name} failed")
  false
end

#parse(line) ⇒ Object (protected)



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/osctld/monitor/process.rb', line 88

def parse(line)
  if /'([^']+)' changed state to \[([^\]]+)\]/ =~ line
    log(:info, :monitor, "Container #{@pool.name}:#{::Regexp.last_match(1)} entered state #{::Regexp.last_match(2)}")
    return { pool: @pool.name, ctid: ::Regexp.last_match(1), state: ::Regexp.last_match(2).downcase.to_sym }

  elsif /'([^']+)' exited with status \[(\d+)\]/ =~ line
    log(:info, :monitor, "Container #{@pool.name}:#{::Regexp.last_match(1)} exited with #{::Regexp.last_match(2)}")

  else
    log(:warn, :monitor, "Line from lxc-monitor not recognized: '#{line}'")
  end

  nil
end

#update_state(change) ⇒ Object (protected)



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
# File 'lib/osctld/monitor/process.rb', line 103

def update_state(change)
  ct = DB::Containers.find(change[:ctid], change[:pool])

  unless ct
    log(:warn, :monitor, "Container #{change[:pool]}:#{change[:ctid]} not found")
    return
  end

  Eventd.report(:state, pool: ct.pool.name, id: ct.id, state: change[:state])

  ct.state = change[:state]
  init_pid = nil

  case ct.state
  when :running
    begin
      init_pid = ContainerControl::Commands::State.run!(ct).init_pid
      ct.ensure_run_conf.init_pid = init_pid
    rescue ContainerControl::Error => e
      log(:warn, :monitor, "Unable to get state of container #{ct.ident}: #{e.message}")
    end

    if init_pid
      Eventd.report(:ct_init_pid, pool: ct.pool.name, id: ct.id, init_pid:)
    end

    Hook.run(ct, :post_start, init_pid: ct.init_pid)

  when :aborting
    # It has happened that ct.run_conf was nil, circumstances unknown
    ct.ensure_run_conf.aborted = true

  when :stopping
    Hook.run(ct, :on_stop)

  when :stopped, :aborted
    ct.mounts.prune
  end
end