cloudflock 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/cloudflock +7 -1
- data/bin/cloudflock-files +2 -14
- data/bin/cloudflock-profile +3 -15
- data/bin/cloudflock-servers +3 -22
- data/bin/cloudflock.default +3 -22
- data/lib/cloudflock/app/common/cleanup/unix.rb +23 -0
- data/lib/cloudflock/app/common/cleanup.rb +107 -0
- data/lib/cloudflock/app/common/exclusions/unix/centos.rb +18 -0
- data/lib/cloudflock/app/common/exclusions/unix/redhat.rb +18 -0
- data/lib/cloudflock/app/common/exclusions/unix.rb +58 -0
- data/lib/cloudflock/app/common/exclusions.rb +57 -0
- data/lib/cloudflock/app/common/platform_action.rb +59 -0
- data/lib/cloudflock/app/common/rackspace.rb +63 -0
- data/lib/cloudflock/app/common/servers.rb +673 -0
- data/lib/cloudflock/app/files-migrate.rb +246 -0
- data/lib/cloudflock/app/server-migrate.rb +327 -0
- data/lib/cloudflock/app/server-profile.rb +130 -0
- data/lib/cloudflock/app.rb +87 -0
- data/lib/cloudflock/error.rb +6 -19
- data/lib/cloudflock/errstr.rb +31 -0
- data/lib/cloudflock/remote/files.rb +82 -22
- data/lib/cloudflock/remote/ssh.rb +234 -278
- data/lib/cloudflock/target/servers/platform.rb +92 -115
- data/lib/cloudflock/target/servers/profile.rb +331 -340
- data/lib/cloudflock/task/server-profile.rb +651 -0
- data/lib/cloudflock.rb +6 -8
- metadata +49 -68
- data/lib/cloudflock/interface/cli/app/common/servers.rb +0 -128
- data/lib/cloudflock/interface/cli/app/files.rb +0 -179
- data/lib/cloudflock/interface/cli/app/servers/migrate.rb +0 -491
- data/lib/cloudflock/interface/cli/app/servers/profile.rb +0 -88
- data/lib/cloudflock/interface/cli/app/servers.rb +0 -2
- data/lib/cloudflock/interface/cli/console.rb +0 -213
- data/lib/cloudflock/interface/cli/opts/servers.rb +0 -20
- data/lib/cloudflock/interface/cli/opts.rb +0 -87
- data/lib/cloudflock/interface/cli.rb +0 -15
- data/lib/cloudflock/target/servers/data/exceptions/base.txt +0 -44
- data/lib/cloudflock/target/servers/data/exceptions/platform/amazon.txt +0 -10
- data/lib/cloudflock/target/servers/data/exceptions/platform/centos.txt +0 -7
- data/lib/cloudflock/target/servers/data/exceptions/platform/debian.txt +0 -0
- data/lib/cloudflock/target/servers/data/exceptions/platform/redhat.txt +0 -7
- data/lib/cloudflock/target/servers/data/exceptions/platform/suse.txt +0 -1
- data/lib/cloudflock/target/servers/data/post-migration/chroot/base.txt +0 -1
- data/lib/cloudflock/target/servers/data/post-migration/chroot/platform/amazon.txt +0 -19
- data/lib/cloudflock/target/servers/data/post-migration/pre/base.txt +0 -3
- data/lib/cloudflock/target/servers/data/post-migration/pre/platform/amazon.txt +0 -4
- data/lib/cloudflock/target/servers/migrate.rb +0 -466
- data/lib/cloudflock/target/servers/platform/v1.rb +0 -97
- data/lib/cloudflock/target/servers/platform/v2.rb +0 -93
- data/lib/cloudflock/target/servers.rb +0 -5
- data/lib/cloudflock/version.rb +0 -3
@@ -1,394 +1,385 @@
|
|
1
1
|
require 'cloudflock/remote/ssh'
|
2
|
+
require 'socket'
|
2
3
|
require 'cpe'
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
class CloudFlock::Target::Servers::Profile
|
19
|
-
# Public: Array containing warnings generated by the info gathering process.
|
20
|
-
attr_reader :warnings
|
21
|
-
|
22
|
-
# Public: Initialize the Profile object.
|
23
|
-
#
|
24
|
-
# shell - An SSH object open to the host to be profiled.
|
25
|
-
#
|
26
|
-
# Raises ArgumentError if passed anything but an SSH object.
|
27
|
-
def initialize(shell)
|
28
|
-
raise ArgumentError unless shell.kind_of? CloudFlock::Remote::SSH
|
29
|
-
|
30
|
-
@shell = shell
|
31
|
-
|
32
|
-
@warnings = []
|
33
|
-
@info = {}
|
34
|
-
end
|
35
|
-
|
36
|
-
# Public: Run all available determinations against the SSH object.
|
37
|
-
#
|
38
|
-
# Returns nothing.
|
39
|
-
def build
|
40
|
-
determine_version
|
41
|
-
determine_arch
|
42
|
-
determine_hostname
|
43
|
-
determine_memory
|
44
|
-
determine_cpu
|
45
|
-
determine_disk
|
46
|
-
determine_ips
|
47
|
-
determine_io
|
48
|
-
determine_web
|
49
|
-
determine_db
|
50
|
-
determine_lib
|
51
|
-
determine_rsync
|
52
|
-
determine_processes
|
53
|
-
end
|
54
|
-
|
55
|
-
# Public: Determine vendor and version of the OS running on the target host,
|
56
|
-
# and create an appropriate CPE object for it, assigning it to @info[:cpe].
|
57
|
-
#
|
58
|
-
# Returns nothing.
|
59
|
-
def determine_version
|
60
|
-
release = @shell.query("CPE", "cat /etc/system-release-cpe")
|
5
|
+
module CloudFlock; module Target; module Servers
|
6
|
+
class Profile
|
7
|
+
# Public: List of linux distributions supported by CloudFlock
|
8
|
+
SUPPORTED_DISTROS = %w{Arch CentOS Debian SUSE Ubuntu RedHat Gentoo}
|
9
|
+
|
10
|
+
# Public: Initialize the Profile object.
|
11
|
+
#
|
12
|
+
# shell - An SSH object which is open to the host which will be profiled.
|
13
|
+
#
|
14
|
+
# Raises TypeError if shell is not of type SSH.
|
15
|
+
def initialize(shell)
|
16
|
+
unless shell.is_a?(CloudFlock::Remote::SSH)
|
17
|
+
raise(TypeError, Errstr::NOT_SSH)
|
18
|
+
end
|
61
19
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
@info[:cpe] = cpe
|
66
|
-
return
|
67
|
-
rescue ArgumentError
|
68
|
-
cpe = CPE.new(part: CPE::OS, product: "linux")
|
20
|
+
@shell = shell
|
21
|
+
@warnings = []
|
22
|
+
@info = {}
|
69
23
|
end
|
70
24
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
when /This is/
|
83
|
-
cpe.vendor = "Gentoo"
|
84
|
-
when /SUSE/
|
85
|
-
cpe.vendor = "openSUSE"
|
86
|
-
when /Ubuntu/
|
87
|
-
cpe.vendor = "Ubuntu"
|
88
|
-
when /Red/
|
89
|
-
cpe.vendor = "Redhat"
|
90
|
-
issue.gsub!(/\.\d.*$/, '')
|
91
|
-
else
|
92
|
-
cpe.vendor = "Unknown"
|
25
|
+
# Public: Build the profile by calling all methods which begin with
|
26
|
+
# 'determine_'.
|
27
|
+
#
|
28
|
+
# Returns nothing.
|
29
|
+
def build
|
30
|
+
methods.select { |x| x =~ /^determine_/ }.each do |method|
|
31
|
+
self.send(method)
|
32
|
+
end
|
33
|
+
methods.select { |x| x =~ /^warning_/ }.each do |method|
|
34
|
+
self.send(method)
|
35
|
+
end
|
93
36
|
end
|
94
37
|
|
95
|
-
|
96
|
-
|
97
|
-
@info
|
98
|
-
|
38
|
+
# Public: Allow access to the list of keys in @info.
|
39
|
+
#
|
40
|
+
# Returns an Array of keys in @info.
|
41
|
+
def keys
|
42
|
+
@info.keys
|
43
|
+
end
|
99
44
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
when /x86_64/
|
108
|
-
@info[:arch] = 'x86_64'
|
109
|
-
when /i\d86/
|
110
|
-
@info[:arch] = 'i386'
|
111
|
-
else
|
112
|
-
@info[:arch] = "Unknown"
|
45
|
+
# Public: Simplify access to @info.
|
46
|
+
#
|
47
|
+
# key - Object to be used as the key in the @info Hash.
|
48
|
+
#
|
49
|
+
# Returns a value stored in @info.
|
50
|
+
def [](key)
|
51
|
+
@info[key]
|
113
52
|
end
|
114
|
-
end
|
115
53
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
54
|
+
# Public: Return server information and warnings as a Hash.
|
55
|
+
#
|
56
|
+
# Returns a Hash.
|
57
|
+
def to_hash
|
58
|
+
@info.merge({warnings: @warnings})
|
59
|
+
end
|
123
60
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
# Determine average mem and swap usage
|
144
|
-
result = {}
|
145
|
-
sar_location = @shell.query("SAR", "which sar 2>/dev/null")
|
146
|
-
sar_command = %w{for l in $(find /var/log/ -name 'sa??'); do sar -r -f $l |
|
147
|
-
grep Average; done | awk '{I+=1; TOT=$2+$3; CACHE+=$5+$6;
|
148
|
-
FREE+=$2; SWAP+=$9;} END {CACHE=CACHE/I; FREE=FREE/I;
|
149
|
-
SWAP=SWAP/I; print (TOT-(CACHE+FREE))/TOT*100,
|
150
|
-
SWAP;}'}.join(' ')
|
151
|
-
|
152
|
-
if sar_location =~ /bin\//
|
153
|
-
sar_usage = @shell.query("HIST_MEM", sar_command)
|
154
|
-
|
155
|
-
if sar_usage =~ /\d \d/
|
156
|
-
hist_mem, hist_swap = sar_usage.split(/ /)
|
157
|
-
result[:mem_used] = hist_mem.to_i
|
158
|
-
result[:swap_used] = hist_swap.to_i
|
61
|
+
private
|
62
|
+
|
63
|
+
# Internal: Determine important statistics relating to the CPU (available
|
64
|
+
# core count, speed).
|
65
|
+
#
|
66
|
+
# Returns nothing.
|
67
|
+
def determine_cpu
|
68
|
+
cpu = @info[:cpu] = {}
|
69
|
+
|
70
|
+
lscpu = @shell.query('LSCPU', 'lscpu')
|
71
|
+
if lscpu.empty?
|
72
|
+
cpuinfo = @shell.query('cat /proc/cpuinfo')
|
73
|
+
count = cpuinfo.lines.select { |l| l =~ /^processor\s*: [0-9]/}
|
74
|
+
speed = cpuinfo.lines.select { |l| l =~ /MHz/ }
|
75
|
+
cpu[:count] = count.size
|
76
|
+
cpu[:speed] = speed[0].to_s.gsub(/.* /, '')
|
77
|
+
else
|
78
|
+
cpu[:count] = lscpu.select { |l| l =~ /CPU\(s\)/ }.gsub(/.* /, '')
|
79
|
+
cpu[:speed] = lscpu.select { |l| l =~ /MHz/ }.gsub(/.* /, '')
|
159
80
|
end
|
160
81
|
end
|
161
82
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
end
|
178
|
-
|
179
|
-
# Public: Determine the amount of disk space in use on the target host and
|
180
|
-
# set that to @info[:disk].
|
181
|
-
#
|
182
|
-
# Returns nothing.
|
183
|
-
def determine_disk
|
184
|
-
# Use a less accurate (tends to inflate) method if du takes too long
|
185
|
-
df_command = "df 2>/dev/null |awk '$1 ~ /\\// {I = I + $3} END {print I}'"
|
186
|
-
disk = @shell.query("DISK_USED_DF", df_command)
|
187
|
-
|
188
|
-
# Result is returned as KiB used. We need GB used.
|
189
|
-
@info[:disk] = disk.to_f / 1000 ** 2
|
190
|
-
end
|
191
|
-
|
192
|
-
# Public: Determine the number of public and private IP addressess in use on
|
193
|
-
# the target host and assign that to @info[:ip].
|
194
|
-
#
|
195
|
-
# Returns nothing.
|
196
|
-
def determine_ips
|
197
|
-
ips = {:private => [], :public => []}
|
83
|
+
# Internal: Determine the number and size of MySQL databases resident on
|
84
|
+
# the target host.
|
85
|
+
#
|
86
|
+
# Returns nothing.
|
87
|
+
def determine_databases
|
88
|
+
db = @info[:db] = {}
|
89
|
+
mysql_count_cmd = 'find /var/lib/mysql* -maxdepth 0 -type d ' \
|
90
|
+
'2>/dev/null|wc -l'
|
91
|
+
db[:count] = @shell.query('DB_MYSQL_COUNT', mysql_count_cmd)
|
92
|
+
db[:count] = db[:count].to_i
|
93
|
+
|
94
|
+
mysql_size_cmd = "du -s /var/lib/mysql 2>/dev/null|awk '{print $1}'"
|
95
|
+
db[:size] = @shell.query('DB_MYSQL_SIZE', mysql_size_cmd)
|
96
|
+
db[:size] = db[:size].to_i
|
97
|
+
end
|
198
98
|
|
199
|
-
|
200
|
-
|
201
|
-
|
99
|
+
# Internal: Determine the amount of disk space in use on the target host.
|
100
|
+
#
|
101
|
+
# Returns nothing.
|
102
|
+
def determine_disk
|
103
|
+
df_cmd = "df 2>/dev/null|awk '$1 ~ /\\// {I=I+$3} END {print I}'"
|
104
|
+
disk = @shell.query('DISK_DF', df_cmd)
|
202
105
|
|
203
|
-
|
204
|
-
|
205
|
-
ips[rfc1918?(ip)] << ip
|
106
|
+
# Result is expected to be in KiB. Convert to GB.
|
107
|
+
@info[:disk] = disk.to_f / 1000 ** 2
|
206
108
|
end
|
207
109
|
|
208
|
-
|
209
|
-
|
110
|
+
# Internal: Attempt to determine which linux distribution the target host
|
111
|
+
# is running.
|
112
|
+
#
|
113
|
+
# Returns nothing.
|
114
|
+
def determine_distribution
|
115
|
+
# Some distros ship with a file containing the CPE for their platform;
|
116
|
+
# this should be used if at all possible.
|
117
|
+
release = @shell.query('CPE', 'cat /etc/system-release-cpe')
|
118
|
+
begin
|
119
|
+
cpe = CPE.parse(release)
|
120
|
+
cpe.version.gsub!(/[^0-9.]/, '')
|
121
|
+
@info[:cpe] = cpe
|
122
|
+
return
|
123
|
+
rescue ArgumentError
|
124
|
+
cpe = CPE.new(part: CPE::OS, product: 'linux')
|
125
|
+
end
|
210
126
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
# Returns nothing.
|
215
|
-
def determine_io
|
216
|
-
io = {}
|
127
|
+
# Fall back to depending on /etc/issue if available
|
128
|
+
issue = @shell.query('ISSUE', 'cat /etc/issue')
|
129
|
+
cpe.vendor = distro_name(issue)
|
217
130
|
|
218
|
-
|
219
|
-
|
131
|
+
# If all else fails, resort to looking in release files
|
132
|
+
if cpe.vendor.empty?
|
133
|
+
release_cmd = "grep -h '^ID=' /etc/[A-Za-z]*[_-][rv]e[lr]*|head -1"
|
134
|
+
release = @shell.query("RELEASE", release_cmd)
|
135
|
+
cpe.vendor = distro_name(release)
|
136
|
+
end
|
220
137
|
|
221
|
-
|
222
|
-
|
138
|
+
# Fall back to "Unknown"
|
139
|
+
cpe.vendor = "" if cpe.vendor.empty?
|
223
140
|
|
224
|
-
|
225
|
-
|
141
|
+
# Version number will be determined from /etc/issue
|
142
|
+
cpe.version = version_number(issue)
|
143
|
+
@info[:cpe] = cpe
|
144
|
+
end
|
226
145
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
def determine_web
|
233
|
-
web = {}
|
234
|
-
|
235
|
-
netstat_command = %w{netstat -ntlp | awk '$4 ~ /:80$/ || $4 ~ /:443$/
|
236
|
-
{sub(/^[^\/]*\//, ""); print $NF}' | head -1}.join(' ')
|
237
|
-
web[:binary] = @shell.query("WEB_NETSTAT", netstat_command)
|
238
|
-
|
239
|
-
unless web[:binary].empty?
|
240
|
-
version_command = "`which #{web[:binary]}` -v | grep version"
|
241
|
-
web[:version] = @shell.query("WEB_VERSION", version_command)
|
242
|
-
web[:version].gsub!(/.*version: /i, '')
|
243
|
-
binary = web[:binary] == "httpd" ? "apachectl" : "apache2ctl"
|
244
|
-
binary << " -S 2>&1"
|
245
|
-
|
246
|
-
web_command = "#{binary} | grep ')' | grep -vi 'default' | wc -l"
|
247
|
-
hosts = @shell.query("WEB_HTTP", web_command)
|
248
|
-
web[:hosts_http] = hosts.to_i
|
249
|
-
|
250
|
-
ssl_command = "#{binary} | grep ':443'|grep -vi 'default' | wc -l"
|
251
|
-
ssl_hosts = @shell.query("WEB_HTTPS", ssl_command)
|
252
|
-
web[:hosts_https] = ssl_hosts.to_i
|
146
|
+
# Internal: Determine the hostname of the target host.
|
147
|
+
#
|
148
|
+
# Returns nothing.
|
149
|
+
def determine_hostname
|
150
|
+
@info[:hostname] = @shell.query('HOST', 'hostname')
|
253
151
|
end
|
254
152
|
|
255
|
-
|
256
|
-
|
153
|
+
# Internal: Determine the amount of historical IO activity on the target
|
154
|
+
# host using sysstat if available.
|
155
|
+
#
|
156
|
+
# Returns nothing.
|
157
|
+
def determine_io
|
158
|
+
io = @info[:io] = {}
|
257
159
|
|
258
|
-
|
259
|
-
|
260
|
-
# supports MySQL.
|
261
|
-
#
|
262
|
-
# Returns nothing.
|
263
|
-
def determine_db
|
264
|
-
db = {}
|
265
|
-
mysql_count = %w{find /var/lib/mysql/* -maxdepth 0 -type d 2>/dev/null |
|
266
|
-
wc -l}.join(' ')
|
267
|
-
db[:count] = @shell.query("DB_MYSQL_COUNT", mysql_count)
|
160
|
+
iostat = @shell.query('IOSTAT', "iostat -c|sed -n 4p|awk '#{print $4}'")
|
161
|
+
io[:wait] = iostat.to_f
|
268
162
|
|
269
|
-
|
270
|
-
|
163
|
+
up = @shell.query('UPTIME', "uptime|sed -e 's/.*up\\([^,]*\\),.*/\\1/'")
|
164
|
+
io[:uptime] = up.chomp
|
165
|
+
end
|
271
166
|
|
272
|
-
|
273
|
-
|
167
|
+
# Internal: Determine IPv4 addresses in use by the target host, splitting
|
168
|
+
# them into public and private groups.
|
169
|
+
#
|
170
|
+
# Returns nothing.
|
171
|
+
def determine_ips
|
172
|
+
ips = @info[:ip] = {private: [], public: []}
|
274
173
|
|
275
|
-
|
276
|
-
|
174
|
+
ifc_cmd = "/sbin/ifconfig|grep 'inet addr'|grep -v ':127'|sed -e " \
|
175
|
+
"'s/.*addr:\([0-9.]*\) .*/\\1/'"
|
176
|
+
ifconfig = @shell.query('IFCONFIG', ifc_cmd)
|
277
177
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
lib = {}
|
178
|
+
ifconfig.each_line do |ip|
|
179
|
+
ip.strip!
|
180
|
+
ips[rfc1918?(ip)] << ip
|
181
|
+
end
|
182
|
+
end
|
284
183
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
184
|
+
# Internal: Determine common libraries installed on the system.
|
185
|
+
#
|
186
|
+
# Returns nothing.
|
187
|
+
def determine_libraries
|
188
|
+
lib = @info[:lib] = {}
|
289
189
|
|
290
|
-
|
291
|
-
|
190
|
+
libc_cmd = "ls -la `find /lib /usr/lib -name 'libc.so*'|head -1`|" \
|
191
|
+
"sed 's/.*-> //'"
|
192
|
+
lib[:libc] = @shell.query('LIBC', libc_cmd)
|
193
|
+
lib[:libc].gsub!(/^.*-|\.so$/, '')
|
292
194
|
|
293
|
-
|
294
|
-
|
295
|
-
lib[:python] = lib[:python].gsub(/^([0-9.]*).*/m, '\1')
|
195
|
+
lib[:perl] = @shell.query('PERL', 'perl -e "print $^V;"')
|
196
|
+
lib[:perl].gsub!(/^v([0-9.]*).*/, '\1')
|
296
197
|
|
297
|
-
|
298
|
-
|
198
|
+
python_cmd = 'python -c "import sys; print sys.version" 2>/dev/null'
|
199
|
+
lib[:python] = @shell.query('PYTHON', python_cmd)
|
200
|
+
lib[:python].gsub!(/([0-9.]*).*/m, '\1')
|
299
201
|
|
300
|
-
|
301
|
-
|
202
|
+
ruby_cmd = 'ruby -e "print RUBY_VERSION" 2>/dev/null'
|
203
|
+
lib[:ruby] = @shell.query('RUBY', ruby_cmd)
|
302
204
|
|
303
|
-
|
304
|
-
|
205
|
+
lib[:php] = @shell.query('PHP', 'php -v 2>/dev/null|head -1')
|
206
|
+
lib[:php].gsub!(/^PHP ([0-9.]*).*/, '\1')
|
207
|
+
end
|
305
208
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
209
|
+
# Internal: Determine the total amount of memory on the target host, the
|
210
|
+
# amount of memory in use, and the amount of swap space being used.
|
211
|
+
#
|
212
|
+
# Returns nothing.
|
213
|
+
def determine_memory
|
214
|
+
result = @info[:memory] = {}
|
215
|
+
|
216
|
+
free_cmd = "free -m|awk '$1 ~ /Mem/ {print $2, $2-$6-$7}; $1 ~ /Swap/ " \
|
217
|
+
"{print $3}'|xargs"
|
218
|
+
mem = @shell.query('MEMORY', free_cmd)
|
219
|
+
total, used, swap = mem.split(/\s+/)
|
220
|
+
|
221
|
+
result[:total] = total.to_i
|
222
|
+
result[:mem_used] = used.to_i
|
223
|
+
result[:swap_used] = swap.to_i
|
224
|
+
result[:swapping?] = swqp.to_i > 0
|
225
|
+
end
|
315
226
|
|
316
|
-
|
227
|
+
# Internal: If the sysstat suite is installed on the target host, determine
|
228
|
+
# the average amount of memory and swap used over whatever historical
|
229
|
+
# period sar is able to represent.
|
230
|
+
#
|
231
|
+
# Returns nothing.
|
232
|
+
def determine_memory_history
|
233
|
+
result = @info[:memory_hist] = {}
|
234
|
+
sar_cmd = "for l in $(find /var/log -name 'sa??');do sar -r -f $l|" \
|
235
|
+
"grep Average;done|awk '{I+=1;TOT=$2+$3;CACHE+=$5+$6;" \
|
236
|
+
"FREE+=$2;SWAP+=$9;} END {CACHE=CACHE/I;FREE=FREE/I;" \
|
237
|
+
"SWAP=SWAP/I;print (TOT-(CACHE+FREE))/TOT*100,SWAP;}'"
|
238
|
+
|
239
|
+
sar_location = @shell.query('SAR_LOCATION', 'which sar 2>/dev/null')
|
240
|
+
if sar_location =~ /bin\//
|
241
|
+
sar_usage = @shell.query('SAR', sar_cmd)
|
242
|
+
|
243
|
+
if sar_usage =~/\d \d/
|
244
|
+
mem, swap = sar_usage.split(/ /)
|
245
|
+
result[:mem_used] = mem
|
246
|
+
result[:swap_used] = swap
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
317
250
|
|
318
|
-
|
319
|
-
|
251
|
+
# Internal: Gather a list of all listening ports on the target host.
|
252
|
+
#
|
253
|
+
# Returns nothing.
|
254
|
+
def determine_ports
|
255
|
+
ports = @info[:ports] = {}
|
256
|
+
|
257
|
+
netstat = @shell.query('NETSTAT', "netstat -ntlp|awk '{print $4, $NF}'")
|
258
|
+
netstat.lines.each do |line|
|
259
|
+
net, process = line.split(/\s+/, 2)
|
260
|
+
process = process.split(/\//, 2)[1]
|
261
|
+
net = net.gsub(/([0-9.:]+):([0-9]+)/, '\1 \2')
|
262
|
+
net, port = net.split(/ /, 2)
|
263
|
+
|
264
|
+
ports[net] ||= {}
|
265
|
+
ports[net][port] = process
|
266
|
+
end
|
267
|
+
end
|
320
268
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
269
|
+
# Internal: Gather a list of running processes on the target host.
|
270
|
+
#
|
271
|
+
# Returns nothing.
|
272
|
+
def determine_processes
|
273
|
+
procs = @shell.query('PROCESSES', 'ps aux')
|
274
|
+
@info[:processes] = procs.gsub(/\r/, '').split(/\n/)
|
275
|
+
end
|
326
276
|
|
327
|
-
|
328
|
-
|
277
|
+
# Internal: Locate rsync on the target host.
|
278
|
+
#
|
279
|
+
# Returns nothing.
|
280
|
+
def determine_rsync
|
281
|
+
rsync = @shell.query('RSYNC', 'which rsync 2>/dev/null')
|
282
|
+
|
283
|
+
if rsync.empty?
|
284
|
+
rsync_cmd = '[ -f /root/.cloudflock/rsync ] && printf ' \
|
285
|
+
'"/root/.rackspace/rsync"'
|
286
|
+
rsync = @shell.query('LOCAL_RSYNC', rsync_cmd)
|
287
|
+
rsync = nil if rsync.empty?
|
288
|
+
end
|
329
289
|
|
330
|
-
|
331
|
-
@warnings << "Server likely to be running Plesk"
|
290
|
+
@info[:rsync] = rsync
|
332
291
|
end
|
333
|
-
|
334
|
-
|
292
|
+
|
293
|
+
# Internal: Determine the architecture of the target host.
|
294
|
+
#
|
295
|
+
# Returns nothing.
|
296
|
+
def determine_system_architecture
|
297
|
+
@info[:arch] = @shell.query('UNAME', 'uname -m')
|
298
|
+
@info[:arch].gsub!(/i\d86/, 'i386')
|
335
299
|
end
|
336
|
-
end
|
337
300
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
301
|
+
# Internal: Determine which web server, if any, is running on the target
|
302
|
+
# host. If the web server is supported, discover how many HTTP/HTTPS
|
303
|
+
# domains are configured on the server.
|
304
|
+
#
|
305
|
+
# Returns nothing.
|
306
|
+
def determine_web
|
307
|
+
web = @info[:web] = {}
|
308
|
+
netstat_cmd = 'netstat -ntlp|awk \'$4 ~ /:80$/ || $4 ~ /:443$/ ' \
|
309
|
+
'{sub (/^[^\/]*\//, ""); print $NF}\'|head -1'
|
310
|
+
web[:binary] = @shell.query('WEB_NETSTAT', netstat_command)
|
311
|
+
|
312
|
+
unless web[:binary].empty?
|
313
|
+
if web[:binary] == 'httpd' || web[:binary] == 'apache2'
|
314
|
+
version_cmd = "`which #{web[:binary]}` -v|grep version"
|
315
|
+
web[:version] = @shell.query('WEB_VERSION', version_cmd)
|
316
|
+
web[:version].gsub!(/.*version: /i, '')
|
317
|
+
|
318
|
+
ctl_cmd = web[:binary] == 'httpd' ? 'apachectl' : 'apache2ctl'
|
319
|
+
ctl_cmd << ' -S 2>&1'
|
320
|
+
|
321
|
+
web_cmd = "#{ctl_cmd}|grep -vi 'default'|wc -l"
|
322
|
+
hosts = @shell.query('WEB_HOSTS', web_cmd)
|
323
|
+
|
324
|
+
ssl = hosts.lines.select { |line| line =~ /:443([^\d]|$)/ }
|
325
|
+
http = hosts.lines - ssl
|
326
|
+
web[:hosts_http] = http.length
|
327
|
+
web[:hosts_https] = https.length
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
346
331
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
332
|
+
# Internal: Check for signs of running Plesk.
|
333
|
+
#
|
334
|
+
# Returns nothing.
|
335
|
+
def warning_plesk
|
336
|
+
unless @info[:processes].to_a.grep(/psa/i).empty?
|
337
|
+
@warnings << "Server likely to be running Plesk"
|
338
|
+
end
|
339
|
+
end
|
353
340
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
341
|
+
# Internal: Check for signs of running cPanel.
|
342
|
+
#
|
343
|
+
# Returns nothing.
|
344
|
+
def warning_webmin
|
345
|
+
unless @info[:processes].to_a.grep(/cpanel/i).empty?
|
346
|
+
@warnings << "Server likely to be running cPanel"
|
347
|
+
end
|
348
|
+
end
|
361
349
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
if version =~ /\d/
|
372
|
-
version.gsub(/^[^\d]*/, '').gsub(/[^\d]*$/, '').gsub(/(\d*\.\d*).*/, '\1')
|
373
|
-
else
|
374
|
-
"-"
|
350
|
+
# Internal: Search for names of supported Linux distributions in a string
|
351
|
+
# which may contain the name of the distribution currently installed on
|
352
|
+
# the target host.
|
353
|
+
#
|
354
|
+
# Returns a String.
|
355
|
+
def distro_name(str)
|
356
|
+
SUPPORTED_DISTROS.select do |distro|
|
357
|
+
Regexp.new(distro, Regexp::IGNORECASE).match(str)
|
358
|
+
end[0].to_s
|
375
359
|
end
|
376
|
-
end
|
377
360
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
elsif octets[0] == "172" && octets[1].to_i >=16 && octets[1].to_i <= 31
|
389
|
-
return :private
|
361
|
+
# Internal: Inspect a String which may contain information regarding the
|
362
|
+
# version of the Linux distribution running on the target host.
|
363
|
+
#
|
364
|
+
# Returns nothing.
|
365
|
+
def version_number(str)
|
366
|
+
if str =~ /\d/
|
367
|
+
str.gsub(/^[^\d]*/, '').gsub(/[^\d]*$/, '').gsub(/(\d*\.\d*).*/, '\1')
|
368
|
+
else
|
369
|
+
'-'
|
370
|
+
end
|
390
371
|
end
|
391
372
|
|
392
|
-
:
|
373
|
+
# Internal: Determine if a v4 IP address belongs to a private (RFC 1918)
|
374
|
+
# network.
|
375
|
+
#
|
376
|
+
# ip - String containing an IP.
|
377
|
+
#
|
378
|
+
# Returns either the symbol :public or :private.
|
379
|
+
def rfc1918?(ip)
|
380
|
+
return :private if Addrinfo.ip(ip).ipv4_private?
|
381
|
+
|
382
|
+
:public
|
383
|
+
end
|
393
384
|
end
|
394
|
-
end
|
385
|
+
end; end; end
|