Class: CloudFlock::Target::Servers::Profile
- Inherits:
-
Object
- Object
- CloudFlock::Target::Servers::Profile
- Defined in:
- lib/cloudflock/target/servers/profile.rb,
lib/cloudflock/error.rb
Overview
Public: Provides methods to create a profile for a given host, mapping it to available public cloud offerings, and reference data gathered during this process.
Examples
# Generate a profile from a shell already logged in to a remote host
profile = Profile.new(ssh_object)
profile.build
# Only determine the memory and I/O statistics for a host
profile = Profile.new(ssh_object)
profile.determine_memory
profile.determine_io
Instance Attribute Summary collapse
-
#warnings ⇒ Object
readonly
Public: Array containing warnings generated by the info gathering process.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Public: Simplify access to @info.
-
#build ⇒ Object
Public: Run all available determinations against the SSH object.
-
#determine_arch ⇒ Object
Public: Determine the architecture of the target host and assign it to @info.
-
#determine_cpu ⇒ Object
Public: Determine the number of CPUs present on the target host and the speed of the processors.
-
#determine_db ⇒ Object
Public: Determine the amount of disk usage attributable to databases, as well as database count, and set this to @info.
-
#determine_disk ⇒ Object
Public: Determine the amount of disk space in use on the target host and set that to @info.
-
#determine_hostname ⇒ Object
Public: Determine the hostname of the target host and assign it to @info.
-
#determine_io ⇒ Object
Public: Determine amount of historical I/O usage via sysstat and set it to @info.
-
#determine_ips ⇒ Object
Public: Determine the number of public and private IP addressess in use on the target host and assign that to @info.
-
#determine_lib ⇒ Object
Public: Gather information about the currently installed libc, ruby, perl, python and php versions on the host, then set these values to @info.
-
#determine_memory ⇒ Object
Public: Determine the available and total memory on the target host as well as historical usage via sar(1), if possible.
-
#determine_processes ⇒ Object
Public: Check the process listing and store it in .
-
#determine_rsync ⇒ Object
Public: Check for the existence of rsync(1) on the host.
-
#determine_version ⇒ Object
Public: Determine vendor and version of the OS running on the target host, and create an appropriate CPE object for it, assigning it to @info.
-
#determine_web ⇒ Object
Public: Determine the web server used on the host, and attempt to enumerate domain names configured on the server for both non-SSL and SSL; set this information to @info.
-
#initialize(shell) ⇒ Profile
constructor
Public: Initialize the Profile object.
-
#keys ⇒ Object
Public: Allow access to the list of keys extant in @info.
-
#rfc1918?(ip) ⇒ Boolean
Internal: Determine whether a given IP resides in a block designated as private by RFC1918.
-
#to_hash ⇒ Object
Public: Return server information and warnings as a Hash.
-
#version_number(version) ⇒ Object
Internal: Deconstruct the version String provided in order to strip out extraneous data before and after the version number.
Constructor Details
#initialize(shell) ⇒ Profile
Public: Initialize the Profile object.
shell - An SSH object open to the host to be profiled.
Raises ArgumentError if passed anything but an SSH object.
27 28 29 30 31 32 33 34 |
# File 'lib/cloudflock/target/servers/profile.rb', line 27 def initialize(shell) raise ArgumentError unless shell.kind_of? CloudFlock::Remote::SSH @shell = shell @warnings = [] @info = {} end |
Instance Attribute Details
#warnings ⇒ Object (readonly)
Public: Array containing warnings generated by the info gathering process.
20 21 22 |
# File 'lib/cloudflock/target/servers/profile.rb', line 20 def warnings @warnings end |
Instance Method Details
#[](key) ⇒ Object
Public: Simplify access to @info.
key - Key to check in @info.
Return value contained in @info by key.
343 344 345 |
# File 'lib/cloudflock/target/servers/profile.rb', line 343 def [](key) @info[key] end |
#build ⇒ Object
Public: Run all available determinations against the SSH object.
Returns nothing.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/cloudflock/target/servers/profile.rb', line 39 def build determine_version determine_arch determine_hostname determine_memory determine_cpu determine_disk determine_ips determine_io determine_web determine_db determine_lib determine_rsync determine_processes end |
#determine_arch ⇒ Object
Public: Determine the architecture of the target host and assign it to @info.
Returns nothing.
104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/cloudflock/target/servers/profile.rb', line 104 def determine_arch uname = @shell.query("UNAME", "uname -m") case uname when /x86_64/ @info[:arch] = 'x86_64' when /i\d86/ @info[:arch] = 'i386' else @info[:arch] = "Unknown" end end |
#determine_cpu ⇒ Object
170 171 172 173 174 175 176 177 |
# File 'lib/cloudflock/target/servers/profile.rb', line 170 def determine_cpu count_command = 'cat /proc/cpuinfo|grep "^processor\\s*: [0-9]"|wc -l' speed_command = 'cat /proc/cpuinfo|grep "MHz"|head -1' cpus = {} cpus[:count] = @shell.query("CPU", count_command).to_i cpus[:speed] = @shell.query("MHZ", speed_command).gsub(/.*: /, '').to_i @info[:cpu] = cpus end |
#determine_db ⇒ Object
Public: Determine the amount of disk usage attributable to databases, as well as database count, and set this to @info. Currently supports MySQL.
Returns nothing.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/cloudflock/target/servers/profile.rb', line 263 def determine_db db = {} mysql_count = %w{find /var/lib/mysql/* -maxdepth 0 -type d 2>/dev/null | wc -l}.join(' ') db[:count] = @shell.query("DB_MYSQL_COUNT", mysql_count) mysql_size = "du -s /var/lib/mysql 2>/dev/null | awk '{print $1}'" db[:size] = @shell.query("DB_MYSQL_SIZE", mysql_size) db[:count] = db[:count].to_i db[:size] = db[:size].to_i @info[:db] = db end |
#determine_disk ⇒ Object
Public: Determine the amount of disk space in use on the target host and set that to @info.
Returns nothing.
183 184 185 186 187 188 189 190 |
# File 'lib/cloudflock/target/servers/profile.rb', line 183 def determine_disk # Use a less accurate (tends to inflate) method if du takes too long df_command = "df 2>/dev/null |awk '$1 ~ /\\// {I = I + $3} END {print I}'" disk = @shell.query("DISK_USED_DF", df_command) # Result is returned as KiB used. We need GB used. @info[:disk] = disk.to_f / 1000 ** 2 end |
#determine_hostname ⇒ Object
Public: Determine the hostname of the target host and assign it to @info
Returns nothing.
120 121 122 |
# File 'lib/cloudflock/target/servers/profile.rb', line 120 def determine_hostname @info[:hostname] = @shell.query("HOST", "hostname") end |
#determine_io ⇒ Object
Public: Determine amount of historical I/O usage via sysstat and set it to @info.
Returns nothing.
215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/cloudflock/target/servers/profile.rb', line 215 def determine_io io = {} iostat = @shell.query("IOSTAT", "iostat -c | sed -n 4p | awk '{print $4}'") io[:wait] = iostat.to_f up = @shell.query("UPTIME", "uptime | sed -e 's/.*up\\([^,]*\\),.*/\\1/'") io[:uptime] = up.chomp @info[:io] = io end |
#determine_ips ⇒ Object
Public: Determine the number of public and private IP addressess in use on the target host and assign that to @info.
Returns nothing.
196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/cloudflock/target/servers/profile.rb', line 196 def determine_ips ips = {:private => [], :public => []} ip_command = %w{/sbin/ifconfig | grep 'inet addr' | egrep -v ':127' | sed -e 's/.*addr:\([0-9.]*\) .*/\1/'}.join(' ') ifconfig = @shell.query("IP_CONFIG", ip_command) ifconfig.each_line do |ip| ip.strip! ips[rfc1918?(ip)] << ip end @info[:ip] = ips end |
#determine_lib ⇒ Object
Public: Gather information about the currently installed libc, ruby, perl, python and php versions on the host, then set these values to @info.
Returns nothing.
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/cloudflock/target/servers/profile.rb', line 282 def determine_lib lib = {} libc_command = %w{ls -al `find /lib /usr/lib -name 'libc.so*' | head -1` | sed 's/.*-> //'}.join(' ') lib[:libc] = @shell.query("LIBC", libc_command) lib[:libc].gsub!(/^.*-|\.so$/, '') lib[:perl] = @shell.query("PERL", "perl -e 'print $^V;'") lib[:perl] = lib[:perl].gsub(/^v([0-9.]*).*/, '\1') python_command = "python -c 'import sys; print sys.version' 2>/dev/null" lib[:python] = @shell.query("PYTHON", python_command) lib[:python] = lib[:python].gsub(/^([0-9.]*).*/m, '\1') ruby_command = "ruby -e 'print RUBY_VERSION' 2>/dev/null" lib[:ruby] = @shell.query("RUBY", ruby_command) lib[:php] = @shell.query("PHP_VER", "php -v 2>/dev/null | head -1") lib[:php] = lib[:php].gsub(/^PHP ([0-9.]*).*/, '\1') @info[:lib] = lib end |
#determine_memory ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/cloudflock/target/servers/profile.rb', line 129 def determine_memory result = {} free = %w{free -m |awk '$1 ~ /Mem/ {print $2, $2-$6-$7}; $1 ~ /Swap/ {print $3}'|xargs}.join(' ') mem = @shell.query("MEMORY", free) total, used, swap = mem.split(/\s+/) result[:total] = total.to_i result[:mem_used] = used.to_i result[:swap_used] = swap.to_i result[:swapping?] = swap.to_i > 0 @info[:memory] = result # Determine average mem and swap usage result = {} sar_location = @shell.query("SAR", "which sar 2>/dev/null") sar_command = %w{for l in $(find /var/log/ -name 'sa??'); do sar -r -f $l | grep Average; done | awk '{I+=1; TOT=$2+$3; CACHE+=$5+$6; FREE+=$2; SWAP+=$9;} END {CACHE=CACHE/I; FREE=FREE/I; SWAP=SWAP/I; print (TOT-(CACHE+FREE))/TOT*100, SWAP;}'}.join(' ') if sar_location =~ /bin\// sar_usage = @shell.query("HIST_MEM", sar_command) if sar_usage =~ /\d \d/ hist_mem, hist_swap = sar_usage.split(/ /) result[:mem_used] = hist_mem.to_i result[:swap_used] = hist_swap.to_i end end @info[:memory_hist] = result end |
#determine_processes ⇒ Object
Public: Check the process listing and store it in
Returns nothing.
324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/cloudflock/target/servers/profile.rb', line 324 def determine_processes ps_command = 'ps aux' processes = @shell.query("PS_LIST", ps_command) @info[:processes] = processes.gsub(/\r/, '').split(/\n/) unless @info[:processes].grep(/psa/i).empty? @warnings << "Server likely to be running Plesk" end unless @info[:processes].grep(/cpanellogd/i).empty? @warnings << "Server likely to be running cPanel" end end |
#determine_rsync ⇒ Object
Public: Check for the existence of rsync(1) on the host. Set @info accordingly.
Returns nothing.
310 311 312 313 314 315 316 317 318 319 |
# File 'lib/cloudflock/target/servers/profile.rb', line 310 def determine_rsync rsync_command = %w{which rsync 2>/dev/null || ([ -f /root/.rackspace/rsync ] && printf '/root/.rackspace/rsync') || printf 'NONE'}.join(' ') rsync = @shell.query("RSYNC", rsync_command) @info[:rsync] = (rsync =~ /NONE/).nil? ? rsync : false end |
#determine_version ⇒ Object
Public: Determine vendor and version of the OS running on the target host, and create an appropriate CPE object for it, assigning it to @info.
Returns nothing.
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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/cloudflock/target/servers/profile.rb', line 59 def determine_version release = @shell.query("CPE", "cat /etc/system-release-cpe") begin cpe = CPE.parse(release) cpe.version.gsub!(/[^0-9.]/, '') @info[:cpe] = cpe return rescue ArgumentError cpe = CPE.new(part: CPE::OS, product: "linux") end issue = @shell.query("ISSUE", "cat /etc/issue") case issue when /Arch/ cpe.vendor = "Arch" when /CentOS/ cpe.vendor = "CentOS" issue.gsub!(/\.\d.*$/, '') when /Debian/ cpe.vendor = "Debian" issue.gsub!(/\.\d.*$/, '') when /This is/ cpe.vendor = "Gentoo" when /SUSE/ cpe.vendor = "openSUSE" when /Ubuntu/ cpe.vendor = "Ubuntu" when /Red/ cpe.vendor = "Redhat" issue.gsub!(/\.\d.*$/, '') else cpe.vendor = "Unknown" end cpe.version = version_number(issue) @info[:cpe] = cpe end |
#determine_web ⇒ Object
Public: Determine the web server used on the host, and attempt to enumerate domain names configured on the server for both non-SSL and SSL; set this information to @info. Presently only Apache is supported.
Returns nothing.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/cloudflock/target/servers/profile.rb', line 232 def determine_web web = {} netstat_command = %w{netstat -ntlp | awk '$4 ~ /:80$/ || $4 ~ /:443$/ {sub(/^[^\/]*\//, ""); print $NF}' | head -1}.join(' ') web[:binary] = @shell.query("WEB_NETSTAT", netstat_command) unless web[:binary].empty? version_command = "`which #{web[:binary]}` -v | grep version" web[:version] = @shell.query("WEB_VERSION", version_command) web[:version].gsub!(/.*version: /i, '') binary = web[:binary] == "httpd" ? "apachectl" : "apache2ctl" binary << " -S 2>&1" web_command = "#{binary} | grep ')' | grep -vi 'default' | wc -l" hosts = @shell.query("WEB_HTTP", web_command) web[:hosts_http] = hosts.to_i ssl_command = "#{binary} | grep ':443'|grep -vi 'default' | wc -l" ssl_hosts = @shell.query("WEB_HTTPS", ssl_command) web[:hosts_https] = ssl_hosts.to_i end @info[:web] = web end |
#keys ⇒ Object
Public: Allow access to the list of keys extant in @info.
Return an Array of keys present in @info.
350 351 352 |
# File 'lib/cloudflock/target/servers/profile.rb', line 350 def keys @info.keys end |
#rfc1918?(ip) ⇒ Boolean
Internal: Determine whether a given IP resides in a block designated as private by RFC1918.
ip - A String containing an IP address.
Returns :private or :public Symbol based on whether the IP is private.
384 385 386 387 388 389 390 391 392 393 |
# File 'lib/cloudflock/target/servers/profile.rb', line 384 def rfc1918?(ip) octets = ip.split /\./ if octets[0] == "10" || (octets[0] == "192" && octets[1] == "168") return :private elsif octets[0] == "172" && octets[1].to_i >=16 && octets[1].to_i <= 31 return :private end :public end |
#to_hash ⇒ Object
Public: Return server information and warnings as a Hash. Useful for calling Hash#merge.
Return info Hash.
358 359 360 |
# File 'lib/cloudflock/target/servers/profile.rb', line 358 def to_hash @info.merge({warnings: @warnings}) end |
#version_number(version) ⇒ Object
Internal: Deconstruct the version String provided in order to strip out extraneous data before and after the version number. Version number strings are defined as beginning with a digit, ending with a digit, and containing nothing but digits and at most one decimal point.
version - A String containing version number of the OS on the target host.
Returns a String containing the parsed version string.
370 371 372 373 374 375 376 |
# File 'lib/cloudflock/target/servers/profile.rb', line 370 def version_number(version) if version =~ /\d/ version.gsub(/^[^\d]*/, '').gsub(/[^\d]*$/, '').gsub(/(\d*\.\d*).*/, '\1') else "-" end end |