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


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

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

63
64
65
66
67
68
69
70
71
72
73
# File 'lib/eye/system.rb', line 63

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

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/eye/system.rb', line 80

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


108
109
110
# File 'lib/eye/system.rb', line 108

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)

27
28
29
30
31
32
33
34
# File 'lib/eye/system.rb', line 27

def pid_alive?(pid)
  if pid
    ::Process.kill(0, pid)
    true
  end
rescue
  false
end

.prepare_env(config = {}) ⇒ Object


133
134
135
136
137
138
139
140
141
# File 'lib/eye/system.rb', line 133

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), …


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/eye/system.rb', line 38

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


112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/eye/system.rb', line 112

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