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.



53
54
55
56
57
58
59
# File 'lib/osctld/monitor/process.rb', line 53

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

Class Method Details

.spawn(ct) ⇒ Object



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

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

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

    SwitchUser.switch_to(
      ct.user.sysusername,
      ct.user.ugid,
      ct.user.homedir,
      File.join(ct.group.full_cgroup_path(ct.user), 'monitor'),
      chown_cgroups: false
    )

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

  out_w.close
  [pid, out_r]
end

.stop_monitord(ct) ⇒ Object



30
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 30

def self.stop_monitord(ct)
  pid = Process.fork do
    SwitchUser.switch_to(
      ct.user.sysusername,
      ct.user.ugid,
      ct.user.homedir,
      File.join(ct.group.full_cgroup_path(ct.user), 'monitor'),
      chown_cgroups: false
    )

    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



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/osctld/monitor/process.rb', line 61

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 #{@user.name}/#{@group.name} failed")
  false
end

#parse(line) ⇒ Object (protected)



83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/osctld/monitor/process.rb', line 83

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

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

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

  nil
end

#update_state(change) ⇒ Object (protected)



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

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]

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

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

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

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