summaryrefslogtreecommitdiff
path: root/lib/oxidized/hook/exec.rb
blob: af2aeb1c1470dad80424ca5d3a41a3bb7514ad78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
class Exec < Oxidized::Hook
  include Process

  def initialize
    super
    @timeout = 60
    @async = false
  end

  def validate_cfg!
    # Syntax check
    if cfg.has_key? "timeout"
      @timeout = cfg.timeout
      raise "invalid timeout value" unless @timeout.is_a?(Integer) &&
                                           @timeout > 0
    end

    if cfg.has_key? "async"
      @async = !!cfg.async
    end

    if cfg.has_key? "cmd"
      @cmd = cfg.cmd
      raise "invalid cmd value" unless @cmd.is_a?(String) || @cmd.is_a?(Array)
    end

  rescue RuntimeError => e
    raise ArgumentError,
      "#{self.class.name}: configuration invalid: #{e.message}"
  end

  def run_hook ctx
    env = make_env ctx
    log "Execute: #{@cmd.inspect}", :debug
    th = Thread.new do
      begin
        run_cmd! env
      rescue => e
        raise e unless @async
      end
    end
    th.join unless @async
  end

  def run_cmd! env
    pid, status = nil, nil
    Timeout.timeout(@timeout) do
      pid = spawn env, @cmd , :unsetenv_others => true
      pid, status = wait2 pid
      unless status.exitstatus.zero?
        msg = "#{@cmd.inspect} failed with exit value #{status.exitstatus}"
        log msg, :error
        raise msg
      end
    end
  rescue TimeoutError
    kill "TERM", pid
    msg = "#{@cmd} timed out"
    log msg, :error
    raise TimeoutError, msg
  end

  def make_env ctx
    env = {
      "OX_EVENT" => ctx.event.to_s
    }
    if ctx.node
      env.merge!(
        "OX_NODE_NAME" => ctx.node.name.to_s,
        "OX_NODE_FROM" => ctx.node.from.to_s,
        "OX_NODE_MSG" => ctx.node.msg.to_s,
        "OX_NODE_GROUP" => ctx.node.group.to_s,
        "OX_EVENT" => ctx.event.to_s,
      )
    end
    if ctx.job
      env.merge!(
        "OX_JOB_STATUS" => ctx.job.status.to_s,
        "OX_JOB_TIME" => ctx.job.time.to_s,
      )
    end
    env
  end
end