cloudflock 0.6.1 → 0.7.0
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.
- 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
|