Module: Eye::System

Defined in:
lib/eye/system.rb

Class Method Summary collapse

Class Method Details

.check_pid_alive(pid) ⇒ Object

Check that pid really exits very fast return result hash


10
11
12
13
14
15
16
17
18
19
20
# File 'lib/eye/system.rb', line 10

def check_pid_alive(pid)
  res = if pid
    ::Process.kill(0, pid)
  else
    false
  end

  {:result => res}
rescue => ex
  {:error => ex}
end

.daemonize(cmd, cfg = {}) ⇒ Object

Daemonize cmd, and detach options:

:pid_file
:working_dir
:environment
:stdin, :stdout, :stderr

57
58
59
60
61
62
63
64
65
66
67
# File 'lib/eye/system.rb', line 57

def daemonize(cmd, cfg = {})
  pid = ::Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))

  {:pid => pid, :exitstatus => 0}

rescue Errno::ENOENT, Errno::EACCES => ex
  {:error => ex}

ensure
  Process.detach(pid) if pid
end

.execute(cmd, cfg = {}) ⇒ Object

Execute cmd with blocking, return status (be careful: inside actor blocks it mailbox, use with defer) options

:working_dir
:environment
:stdin, :stdout, :stderr

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/eye/system.rb', line 74

def execute(cmd, cfg = {})
  pid = ::Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))

  timeout = cfg[:timeout] || 1.second
  status = 0

  Timeout.timeout(timeout) do
    _, st = Process.waitpid2(pid)
    status = st.exitstatus || st.termsig
  end

  {:pid => pid, :exitstatus => status}

rescue Timeout::Error => ex
  if pid
    warn "[#{cfg[:name]}] sending :KILL signal to <#{pid}> due to timeout (#{timeout}s)"
    send_signal(pid, 9)
  end
  {:error => ex}

rescue Errno::ENOENT, Errno::EACCES => ex
  {:error => ex}

ensure
  Process.detach(pid) if pid
end

.normalized_file(file, working_dir = nil) ⇒ Object

normalize file


102
103
104
# File 'lib/eye/system.rb', line 102

def normalized_file(file, working_dir = nil)
  File.expand_path(file, working_dir)
end

.pid_alive?(pid) ⇒ Boolean

Check that pid really exits very fast return true/false

Returns:

  • (Boolean)

25
26
27
28
# File 'lib/eye/system.rb', line 25

def pid_alive?(pid)
  res = check_pid_alive(pid)
  !!res[:result]
end

.prepare_env(config = {}) ⇒ Object


127
128
129
130
131
132
133
134
135
# File 'lib/eye/system.rb', line 127

def prepare_env(config = {})
  env = {}

  (config[:environment] || {}).each do |k,v|
    env[k.to_s] = v && v.to_s
  end

  env
end

.send_signal(pid, code = :TERM) ⇒ Object

Send signal to process (uses for kill) code: TERM(15), KILL(9), QUIT(3), …


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/eye/system.rb', line 32

def send_signal(pid, code = :TERM)
  code = 0 if code == '0'
  if code.to_s.to_i != 0
    code = code.to_i
    code = -code if code < 0
  end
  code = code.to_s.upcase if code.is_a?(String) || code.is_a?(Symbol)

  if pid
    ::Process.kill(code, pid)
    {:result => :ok}
  else
    {:error => Exception.new('no_pid')}
  end

rescue => ex
  {:error => ex}
end

.spawn_options(config = {}) ⇒ Object


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/eye/system.rb', line 106

def spawn_options(config = {})
  options = {
    pgroup: true,
    chdir: config[:working_dir] || '/'
  }

  options[:out]   = [config[:stdout], 'a'] if config[:stdout]
  options[:err]   = [config[:stderr], 'a'] if config[:stderr]
  options[:in]    = config[:stdin] if config[:stdin]
  options[:umask] = config[:umask] if config[:umask]
  options[:close_others] = false if config[:preserve_fds]
  options[:unsetenv_others] = true if config[:clear_env]

  if Eye::Local.root?
    options[:uid] = Etc.getpwnam(config[:uid]).uid if config[:uid]
    options[:gid] = Etc.getgrnam(config[:gid]).gid if config[:gid]
  end

  options
end