hawatel_ps 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +4 -0
  5. data/.yardopts +1 -0
  6. data/CONTRIBUTING.md +74 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +184 -0
  10. data/Rakefile +12 -0
  11. data/hawatel_ps.gemspec +29 -0
  12. data/lib/hawatel_ps/linux/proc_control.rb +75 -0
  13. data/lib/hawatel_ps/linux/proc_fetch.rb +405 -0
  14. data/lib/hawatel_ps/linux/proc_info.rb +53 -0
  15. data/lib/hawatel_ps/linux/proc_table.rb +124 -0
  16. data/lib/hawatel_ps/linux.rb +4 -0
  17. data/lib/hawatel_ps/shared/hawatelps_exception.rb +21 -0
  18. data/lib/hawatel_ps/version.rb +3 -0
  19. data/lib/hawatel_ps/windows/proc_control.rb +67 -0
  20. data/lib/hawatel_ps/windows/proc_fetch.rb +217 -0
  21. data/lib/hawatel_ps/windows/proc_info.rb +51 -0
  22. data/lib/hawatel_ps/windows/proc_table.rb +138 -0
  23. data/lib/hawatel_ps/windows/wmi/wmi_cli.rb +65 -0
  24. data/lib/hawatel_ps/windows/wmi/wmi_exception.rb +23 -0
  25. data/lib/hawatel_ps/windows/wmi/wmi_instance.rb +56 -0
  26. data/lib/hawatel_ps/windows.rb +5 -0
  27. data/lib/hawatel_ps.rb +34 -0
  28. data/spec/hawatel_ps_spec.rb +11 -0
  29. data/spec/linux/bdd/proc_spec.rb +54 -0
  30. data/spec/linux/factories/etc/passwd +32 -0
  31. data/spec/linux/factories/proc/1761/cmdline +0 -0
  32. data/spec/linux/factories/proc/1761/environ +0 -0
  33. data/spec/linux/factories/proc/1761/io +7 -0
  34. data/spec/linux/factories/proc/1761/limits +17 -0
  35. data/spec/linux/factories/proc/1761/stat +1 -0
  36. data/spec/linux/factories/proc/1761/status +46 -0
  37. data/spec/linux/factories/proc/meminfo +45 -0
  38. data/spec/linux/factories/proc/net/tcp +7 -0
  39. data/spec/linux/factories/proc/net/udp +8 -0
  40. data/spec/linux/factories/proc/uptime +1 -0
  41. data/spec/linux/support/stub_dir.rb +33 -0
  42. data/spec/linux/support/stub_file.rb +107 -0
  43. data/spec/linux/tdd/proc_fetch_spec.rb +107 -0
  44. data/spec/linux/tdd/proc_table_spec.rb +85 -0
  45. data/spec/shared/hawatelps_exception_spec.rb +13 -0
  46. data/spec/spec_helper.rb +16 -0
  47. data/spec/windows/bdd/proc_spec.rb +119 -0
  48. data/spec/windows/factories/proc_fetch_factorie.rb +76 -0
  49. data/spec/windows/tdd/proc_control_spec.rb +36 -0
  50. data/spec/windows/tdd/proc_fetch_spec.rb +73 -0
  51. data/spec/windows/tdd/proc_table_spec.rb +71 -0
  52. data/spec/windows/tdd/wmi_spec.rb +59 -0
  53. metadata +181 -0
@@ -0,0 +1,217 @@
1
+ module HawatelPS
2
+ module Windows
3
+ ##
4
+ # = Process Fetch
5
+ #
6
+ # Provides functionality to fetch process information from raw source using WMI client.
7
+ class ProcFetch
8
+ class << self
9
+ # Return attributes of all processes from WMI
10
+ #
11
+ # Each process has attributes which are standardized in this document:
12
+ # https://msdn.microsoft.com/en-us/library/windows/desktop/aa394372
13
+ # Each attribute name is converted to lowercase.
14
+ #
15
+ # @example Get process list (access to attributes by index array)
16
+ # processes = get_process()
17
+ # processes.each do | process |
18
+ # pid = process['processid']
19
+ # name = process['name']
20
+ # puts "#{pid.to_s.ljust(10)} #{name}"
21
+ # end
22
+ #
23
+ # @example Get process list (access to attributes by methods)
24
+ # processes = get_process()
25
+ # processes.each do | process |
26
+ # pid = process.processid
27
+ # name = process.name
28
+ # puts "#{pid.to_s.ljust(10)} #{name}"
29
+ # end
30
+ #
31
+ # @return [Array<Hash>]
32
+ def get_process(args = nil)
33
+ if args.nil?
34
+ wql = prepare_wql("SELECT * FROM Win32_Process")
35
+ else
36
+ wql = prepare_wql('SELECT * FROM Win32_Process', args)
37
+ end
38
+
39
+ proc_table = Array.new
40
+
41
+ # TODO maybe the better way will be put user info to class variable?
42
+ @users_list = get_users
43
+ @system_info = system_info
44
+ @memory_total = @system_info[:totalvisiblememorysize]
45
+ @system_idle_time = system_idle_time
46
+
47
+ WmiCli.new.query(wql).each do |proc_instance|
48
+ proc = extract_wmi_property(proc_instance)
49
+ # if proces no longer exists it won't be added to the resulting array
50
+ # sometimes it happens when the Win32_Process query returned process but
51
+ # when this program tries invoke execMethod_ on it the WmiCli class raises an exception
52
+ # because the process disappeared
53
+ proc_table.push(proc) if !proc.nil?
54
+ end
55
+ proc_table
56
+ end
57
+
58
+ private
59
+
60
+ # Prepare WMI Query Language
61
+ # @param query [String] WQL string
62
+ # @param args [Hash] conditions to WHERE clause (conditions are combined only with AND operator)
63
+ # @option name [Type] :opt description
64
+ # @example
65
+ # prepare_wql('SELECT * FROM Win32_Process')
66
+ # prepare_wql('SELECT * FROM Win32_Process', {:processid => 1020})
67
+ # prepare_wql('SELECT * FROM Win32_Process', {:name => 'notepad.exe', :executablepath => 'C:\\\\WINDOWS\\\\system32\\\\notepad.exe'})
68
+ # @return [String] WQL string
69
+ def prepare_wql(query, args = nil)
70
+ if args.nil?
71
+ return query
72
+ else
73
+ query += " WHERE "
74
+ args.each_with_index do |(k, v), index|
75
+ if index == 0 && args.length == 1
76
+ query += "#{k.to_s.downcase} = '#{v}'"
77
+ elsif index == args.length - 1
78
+ query += "#{k.to_s.downcase} = '#{v}'"
79
+ else
80
+ query += "#{k.to_s.downcase} = '#{v}' AND "
81
+ end
82
+ end
83
+ return query
84
+ end
85
+ end
86
+
87
+ # Get property from WIN32OLE object about process
88
+ # @param wmi_object [WmiCli::Instance] process instance represented by WMI object
89
+ # @example
90
+ # extract_wmi_property(wmi_object)
91
+ # @return [Hash]
92
+ def extract_wmi_property(wmi_object)
93
+ property_map = wmi_object.properties.dup
94
+ property_map[:wmi_object] = wmi_object.wmi_ole_object
95
+ property_map[:childs] = Array.new
96
+
97
+ property_map[:sid] = get_owner_sid(wmi_object)
98
+
99
+ get_owner(property_map)
100
+ property_map[:availablevirtualsize] = get_avail_virtual_size(wmi_object)
101
+ property_map[:memorypercent] = memory_percent(@memory_total, property_map[:workingsetsize])
102
+
103
+ property_map[:cpupercent] = cpu_percent(cpu_time(
104
+ :usermodetime => property_map[:usermodetime],
105
+ :kernelmodetime => property_map[:kernelmodetime]))
106
+
107
+ hash_value_to_string(property_map)
108
+
109
+ property_map.delete(:status) if property_map.key?(:status)
110
+
111
+ property_map
112
+ end
113
+
114
+ # Convert hash values to string if is the Integer type
115
+ # @param hash [Hash]
116
+ def hash_value_to_string(hash)
117
+ hash.each {|k,v| hash[k] = v.to_s if v.is_a?(Integer)}
118
+ end
119
+
120
+ # Get users list from Win32_UserAccount class
121
+ # @return [Hash] @users_list
122
+ def get_users
123
+ users_list = Hash.new
124
+ WmiCli.new.query('SELECT * FROM Win32_UserAccount').each do |user|
125
+ users_list[user.properties[:sid]] = user.properties if !user.nil?
126
+ end
127
+ users_list
128
+ end
129
+
130
+ # Find information about user
131
+ # instance variable @users_list must be set {get_users}
132
+ # @param property_map [Hash] Atributes of process
133
+ def get_owner(property_map)
134
+ property_map[:user] = nil
135
+ property_map[:domain] = nil
136
+
137
+ if !property_map[:sid].nil? and !@users_list[property_map[:sid]].nil?
138
+ property_map[:user] = @users_list[property_map[:sid]][:name]
139
+ property_map[:domain] = @users_list[property_map[:sid]][:domain]
140
+ end
141
+ end
142
+
143
+ # Invoke GetOwnerSid method of the Win32_Process class
144
+ # @see https://msdn.microsoft.com/pl-pl/library/windows/desktop/aa390460
145
+ # @param wmi_object [WmiCli::Instance] process instance represented by WMI object
146
+ # @return [String] SID of user
147
+ # @reutrn [nil] if wmi_object no longer exists
148
+ def get_owner_sid(wmi_object)
149
+ # TODO performance problem (it takes ~10 seconds but the native wmi takes similar time)
150
+ owner = wmi_object.execMethod('GetOwnerSid')
151
+ return owner.Sid if !owner.nil?
152
+ rescue WmiCliException
153
+ return nil
154
+ end
155
+
156
+ # Invoke GetAvailableVirtualSize method of the Win32_Process class
157
+ # @see https://msdn.microsoft.com/en-us/library/windows/desktop/dn434274
158
+ # @param wmi_object [WmiCli::Instance] process instance represented by WMI object
159
+ # @return [String] AvailableVirtualSize from WMI
160
+ # @reutrn [nil] if wmi_object no longer exists
161
+ def get_avail_virtual_size(wmi_object)
162
+ obj = wmi_object.execMethod('GetAvailableVirtualSize')
163
+ return obj.AvailableVirtualSize.to_s if !obj.nil?
164
+ rescue WmiCliException
165
+ return nil
166
+ end
167
+
168
+ # System information from Win32_OperatingSystem class
169
+ # @return [Hash]
170
+ def system_info
171
+ WmiCli.new.query('SELECT * FROM Win32_OperatingSystem').each do |result|
172
+ return result.properties if !result.nil?
173
+ end
174
+ end
175
+
176
+ # Return percent of memory usage by process
177
+ # @return [String]
178
+ def memory_percent(mem_total_kb, workingsetsize)
179
+ if !mem_total_kb.nil? && !workingsetsize.nil? && mem_total_kb.to_i > 0
180
+ rss_kb = workingsetsize.to_f / 1024
181
+ return (rss_kb / mem_total_kb.to_f * 100).round(2).to_s
182
+ end
183
+ end
184
+
185
+ # Calculate cpu time for System Idle Process
186
+ # @return [Integer] system idle time in seconds
187
+ def system_idle_time
188
+ WmiCli.new.query("SELECT KernelModeTime FROM Win32_Process WHERE ProcessId = '0'").each do |idle|
189
+ return (idle.properties[:kernelmodetime].to_i / 10000000)
190
+ end
191
+ return nil
192
+ end
193
+
194
+ # Calculate %CPU usage per process
195
+ # @param cpu_time [String/Integer] CPU time consumed by process since system boot
196
+ # @return [String] %CPU usage per process since system boot
197
+ def cpu_percent(cpu_time)
198
+ if !cpu_time.zero?
199
+ return (( cpu_time.to_f / @system_idle_time.to_f) * 100).round(2).to_s
200
+ else
201
+ return "0.0"
202
+ end
203
+ end
204
+
205
+ # Reports processor use time, in seconds, for each process running on a computer.
206
+ # @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa394599(v=vs.85)
207
+ # @param args [Hash] attributes
208
+ # @option opt [String/Integer] User Mode Time
209
+ # @option opt [String/Integer] Kernel Mode Time
210
+ # @return [Integer] processor time for a process in seconds
211
+ def cpu_time(args)
212
+ return ((args[:usermodetime].to_i + args[:kernelmodetime].to_i) / 10000000)
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,51 @@
1
+ module HawatelPS
2
+ module Windows
3
+ class ProcInfo < ProcControl
4
+ # Process instance with attributes of that process
5
+ # @param proc_attrs [Hash] attributes of the process
6
+ # @return [void]
7
+ def initialize(proc_attrs)
8
+ @proc_attrs = proc_attrs
9
+ define_attributes(proc_attrs)
10
+ end
11
+
12
+ # Make attributes of public.
13
+ # Access to process attribute from an object instance by index of array.
14
+ # @example
15
+ # p = ProcInfo.new(proc_attrs)
16
+ # puts p['processid']
17
+ def [](key)
18
+ key = key.to_s.downcase.to_sym if !key.is_a?(Symbol)
19
+ @proc_attrs[key.downcase]
20
+ end
21
+
22
+ # Calls the given block once for each element in self, passing that element as a parameter.
23
+ # @param &block
24
+ # @example print all attributes of process
25
+ # p = ProcInfo.new(proc_attrs)
26
+ # proc.each {|key, val| puts "#{key} - #{val}"}
27
+ # @return An Enumerator is returned if no block is given.
28
+ def each(&block)
29
+ @proc_attrs.each(&block)
30
+ end
31
+
32
+ # @see ProcInfo#define_attributes
33
+ def metaclasses
34
+ class << self; self; end
35
+ end
36
+
37
+ private
38
+ # Make attributes of public.
39
+ # Access to process attribute from an object instance by public method where names of attributes are methods.
40
+ # @example
41
+ # p = ProcInfo.new(proc_attrs)
42
+ # puts p.processid
43
+ def define_attributes(hash)
44
+ hash.each_pair do |key, value|
45
+ metaclasses.send(:attr_reader, key.to_sym)
46
+ instance_variable_set("@#{key}", value)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,138 @@
1
+ module HawatelPS
2
+ module Windows
3
+ class ProcTable
4
+ class << self
5
+
6
+ # Return attributes of searched process based on pid
7
+ # @example
8
+ # search_by_pid(1761)
9
+ # @param [Integer] pid of process
10
+ # @return [ProcInfo]
11
+ def search_by_pid(pid)
12
+ find_by_pid(pid)
13
+ @proc_table.each do |process|
14
+ return process if process.processid.to_s == pid.to_s
15
+ end
16
+ return nil
17
+ end
18
+
19
+
20
+ # Return attributes of searched process based on name or cmdline
21
+ # @example
22
+ # search_by_name('java.exe')
23
+ # search_by_name('/^regex/')
24
+ # @param process_name[String] name of process
25
+ # @return [Array<ProcInfo>]
26
+ def search_by_name(process_name)
27
+ if process_name =~ /^\/.*\/$/
28
+ process_name.slice!(0)
29
+ process_name = Regexp.new(/#{process_name.chop}/)
30
+ find_all
31
+ else
32
+ find_by_name(process_name)
33
+ end
34
+
35
+ process_list = Array.new
36
+
37
+ @proc_table.each do |process|
38
+ if process_name.is_a? Regexp
39
+ process_list << process if process.name =~ process_name || process.commandline =~ process_name
40
+ else
41
+ process_list << process if process.name.to_s.downcase == "#{process_name.to_s.downcase}" || process.commandline.to_s.downcase == "#{process_name.to_s.downcase}"
42
+ end
43
+ end
44
+
45
+ process_list = nil if process_list.empty?
46
+
47
+ return process_list
48
+ end
49
+
50
+ # Return attributes of searched by process
51
+ #
52
+ # @example
53
+ # search_by_condition(:attrs => 'workingsetsize', :oper => '<', value => '10000')
54
+ #
55
+ # @param args[Hash] attributes for search condition
56
+ # @attrs [String], name of process attribute (first expression for if)
57
+ # @oper [String], operatator, available options: >,<,>=,<=,==,!=
58
+ # @value [String], value comparable (second expression for if)
59
+ #
60
+ # @return [Array<ProcInfo>]
61
+ def search_by_condition(args)
62
+ find_all
63
+
64
+ attrs = args[:attr]
65
+ oper = args[:oper]
66
+ value = args[:value]
67
+ process_list = Array.new
68
+ @proc_table.each do |process|
69
+ if oper == '>'
70
+ process_list << process if process[:"#{attrs}"] > value
71
+ elsif oper == '<'
72
+ process_list << process if process[:"#{attrs}"] < value
73
+ elsif oper == '>='
74
+ process_list << process if process[:"#{attrs}"] >= value
75
+ elsif oper == '<='
76
+ process_list << process if process[:"#{attrs}"] <= value
77
+ elsif oper == '=='
78
+ process_list << process if process[:"#{attrs}"] == value
79
+ elsif oper == '!='
80
+ process_list << process if process[:"#{attrs}"] != value
81
+ end
82
+ end
83
+
84
+ process_list = nil if process_list.empty?
85
+
86
+ return process_list
87
+ end
88
+
89
+ # Return all process instances
90
+ # @return [Array<ProcInfo>]
91
+ def proc_table
92
+ find_all
93
+ return @proc_table
94
+ end
95
+
96
+ private
97
+ # Refresh processes array by pid
98
+ def find_by_pid(pid)
99
+ @proc_table = Array.new
100
+ ProcFetch.get_process(:processid => pid).each do |proc_attrs|
101
+ @proc_table.push(ProcInfo.new(proc_attrs))
102
+ end
103
+ childs_tree
104
+ end
105
+
106
+ # Refresh processes array by name
107
+ def find_by_name(name)
108
+ @proc_table = Array.new
109
+ ProcFetch.get_process({:name => name}).each do |proc_attrs|
110
+ @proc_table.push(ProcInfo.new(proc_attrs))
111
+ end
112
+ childs_tree
113
+ end
114
+
115
+ # Refresh processes array
116
+ def find_all
117
+ @proc_table = Array.new
118
+ ProcFetch.get_process.each do |proc_attrs|
119
+ @proc_table.push(ProcInfo.new(proc_attrs))
120
+ end
121
+ childs_tree
122
+ end
123
+
124
+ # Get process childs
125
+ def childs_tree
126
+ @proc_table.each do |proc_parent|
127
+ @proc_table.each do |proc_child|
128
+ if proc_parent.processid === proc_child.parentprocessid
129
+ proc_parent[:childs].push(proc_child)
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,65 @@
1
+ require 'win32ole'
2
+ require 'hawatel_ps/windows/wmi/wmi_instance'
3
+ require 'hawatel_ps/windows/wmi/wmi_exception'
4
+
5
+ module HawatelPS
6
+ module Windows
7
+ ##
8
+ # = Windows Management Instrumentation Client
9
+ #
10
+ # This is wrapper for WMI with limited functionalities (only call queries)
11
+ class WmiCli
12
+ # Init WMI namespace
13
+ # @param namespace [String] WMI namespace
14
+ def initialize(namespace = nil)
15
+ @namespace = namespace.nil? ? 'root/cimv2' : namespace
16
+ @session = nil
17
+ end
18
+
19
+ # Call WMI query
20
+ # @param wql_query [String] WMI Query Language string
21
+ # @example
22
+ # WmiCli.new.query('SELECT * FROM Win32_Process')
23
+ # @raise [WmiCliException] if WQL Query is wrong
24
+ # @return [WmiCli::Instance]
25
+ def query(wql_query)
26
+ connect_to_namespace
27
+ results = @session.ExecQuery(wql_query)
28
+
29
+ wmi_ole_instances = create_wmi_ole_instances(results)
30
+ rescue WIN32OLERuntimeError => ex
31
+ raise WmiCliException, :exception => ex, :message => "Wrong result from WQL Query = '#{wql_query}'."
32
+ end
33
+
34
+ private
35
+
36
+ # Connect to the WMI on the local server
37
+ # @example
38
+ # connect_to_namespace
39
+ # @raise [WIN32OLERuntimeError] if problem with connection to the local server
40
+ # @return [WIN32OLE]
41
+ def connect_to_namespace
42
+ if @session.nil?
43
+ locator = WIN32OLE.new("WbemScripting.SWbemLocator")
44
+ @session = locator.ConnectServer('.', @namespace)
45
+ end
46
+ rescue WIN32OLERuntimeError => ex
47
+ raise WmiCliException, :exception => ex, :message => "Cannot connect to namespace '#{@namespace}'."
48
+ end
49
+
50
+ # Create the WMI32OLE instance from a data set.
51
+ # @param dataset [WMI32OLE] List of WMI objects
52
+ # @example
53
+ # results = @session.ExecQuery(wql_query)
54
+ # wmi_ole_instances = create_wmi_ole_instances(results)
55
+ # @return [Array<WmiCli::Instance>]
56
+ def create_wmi_ole_instances(dataset)
57
+ instances = []
58
+ dataset.each do |wmi_object|
59
+ instances.push(Instance.new(wmi_object))
60
+ end
61
+ instances
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,23 @@
1
+ module HawatelPS
2
+ module Windows
3
+ class WmiCliException < Exception
4
+ # Custom exception
5
+ # @param args [Hash] the options to create a custom exception message
6
+ # @option :exception [Exception] Native Exception object
7
+ # @option :message [String] Custom message
8
+ # @return [void]
9
+ def initialize(args = {:exception => nil, :message => nil})
10
+ super(exception_enrichment(args))
11
+ end
12
+
13
+ private
14
+ def exception_enrichment(args)
15
+ error_message = ''
16
+ error_message += args[:message] unless args[:message].nil?
17
+ error_message +=
18
+ "\nNative exception from '#{args[:exception].class}':\n#{args[:exception].message}" unless args[:exception].nil?
19
+ return error_message
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ module HawatelPS
2
+ module Windows
3
+ class WmiCli
4
+ ##
5
+ # = Instance of Windows Management Instrumentation client
6
+ #
7
+ # Container of single WIN32OLE object wih parameters of this object
8
+ #
9
+ # @!attribute [r] wmi_ole_object
10
+ # @return [WIN32OLE] WMI Object
11
+ # @!attribute [r] properties
12
+ # @return [Hash] Properties from WIN32OLE object
13
+ class Instance
14
+ attr_reader :wmi_ole_object, :properties
15
+
16
+ # Create instance of WmiClient class with WIN32OLE object
17
+ # @param wmi_ole_object [WIN32OLE] Single WMI32OLE object
18
+ def initialize(wmi_ole_object)
19
+ @wmi_ole_object = wmi_ole_object
20
+ @properties = extract_props_to_hash(wmi_ole_object)
21
+ end
22
+
23
+ # Execute WIN32OLE method
24
+ # @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa393774
25
+ # @param name [String] WMI method name assigned to WIN32OLE object
26
+ # @example Object if from Win32_Process class and it has 'GetOwner' method
27
+ # wmi_object.execMethod('GetOwner')
28
+ # @return [WIN32OLE]
29
+ def execMethod(name)
30
+ result = @wmi_ole_object.execMethod_(name) if @wmi_ole_object.ole_respond_to?('execMethod_')
31
+ rescue WIN32OLERuntimeError => ex
32
+ raise WmiCliException, :exception => ex, :message => "Cannot invoke execMethod_('#{name}')"
33
+ end
34
+
35
+ private
36
+
37
+ # Get property from WIN32OLE object
38
+ # @param wmi_object [WIN32OLE] WMI object
39
+ # @example
40
+ # extract_props_to_hash(wmi_object)
41
+ # @return [Hash]
42
+ def extract_props_to_hash(wmi_obj)
43
+ properties = {}
44
+ #binding.pry
45
+ if wmi_obj.ole_respond_to?('properties_')
46
+ wmi_obj.properties_.each do |property|
47
+ properties[property.name.downcase.to_sym] = property.value
48
+ end
49
+ properties.freeze
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ require 'hawatel_ps/windows/proc_fetch'
2
+ require 'hawatel_ps/windows/proc_control'
3
+ require 'hawatel_ps/windows/proc_info'
4
+ require 'hawatel_ps/windows/proc_table'
5
+ require 'hawatel_ps/windows/wmi/wmi_cli'
data/lib/hawatel_ps.rb ADDED
@@ -0,0 +1,34 @@
1
+ require "hawatel_ps/version"
2
+ require "hawatel_ps/linux" if RUBY_PLATFORM =~ /linux/
3
+ require "hawatel_ps/windows" if RUBY_PLATFORM =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
4
+ require "hawatel_ps/shared/hawatelps_exception"
5
+
6
+ module HawatelPS
7
+
8
+ def self.search_by_pid(pid)
9
+ HawatelPS::platform::ProcTable.search_by_pid(pid)
10
+ end
11
+
12
+ def self.search_by_name(name)
13
+ HawatelPS::platform::ProcTable.search_by_name(name)
14
+ end
15
+
16
+ def self.search_by_condition(args)
17
+ HawatelPS::platform::ProcTable.search_by_condition(args)
18
+ end
19
+
20
+ def self.proc_table
21
+ HawatelPS::platform::ProcTable.proc_table
22
+ end
23
+
24
+ def self.platform
25
+ if RUBY_PLATFORM =~ /linux/
26
+ Linux
27
+ elsif RUBY_PLATFORM =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
28
+ Windows
29
+ else
30
+ raise HawatelPSException.new({:message => "Your OS(#{RUBY_PLATFORM}) is not supported!"})
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe HawatelPs do
4
+ it 'has a version number' do
5
+ expect(HawatelPs::VERSION).not_to be nil
6
+ end
7
+
8
+ it 'does something useful' do
9
+ expect(false).to eq(true)
10
+ end
11
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe HawatelPS::Linux::ProcFetch do
4
+
5
+ it "list processes" do
6
+ processes = HawatelPS.proc_table
7
+ processes.each do |process|
8
+ expect(process.pid).to be_a_kind_of(Integer)
9
+ end
10
+ expect(processes.size).to be >= 2
11
+ end
12
+
13
+ it "search process by pid" do
14
+ pid = child(5)
15
+ process = HawatelPS.search_by_pid(pid)
16
+ expect(process[:pid]).to eq(pid)
17
+ end
18
+
19
+ it "search process by name" do
20
+ pid = child(5)
21
+ child_exist = 0
22
+ processes = HawatelPS.search_by_name('/ruby/')
23
+ processes.each do |process|
24
+ child_exist= 1 if process.pid == pid
25
+ end
26
+ expect(processes.size).to be >= 1
27
+ expect(child_exist).to eq(1)
28
+ end
29
+
30
+ it "search process by condition" do
31
+ processes = HawatelPS.search_by_condition(:attr => 'pid', :oper => '>', :value => '1' )
32
+ expect(processes.size).to be >= 2
33
+ end
34
+
35
+ it "suspend & resume and terminate process" do
36
+ pid = child(5)
37
+ process = HawatelPS.search_by_pid(pid)
38
+ suspend_status = process.suspend
39
+ resume_status = process.resume
40
+ terminate_status = process.terminate
41
+ expect(suspend_status).to eq('stopped')
42
+ expect(resume_status).to match(/(sleeping|running)/)
43
+ expect(terminate_status).to match(/(terminated|zombie)/)
44
+ end
45
+
46
+ end
47
+
48
+ private
49
+ def child(timeout)
50
+ pid = fork do
51
+ sleep(timeout)
52
+ exit
53
+ end
54
+ end