cloudflock 0.4.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.
- data/bin/flock +32 -0
- data/bin/flock-profile +17 -0
- data/bin/flock-servers +24 -0
- data/bin/flock.default +24 -0
- data/lib/cloudflock/error.rb +26 -0
- data/lib/cloudflock/interface/cli/app/common/servers.rb +128 -0
- data/lib/cloudflock/interface/cli/app/servers/migrate.rb +357 -0
- data/lib/cloudflock/interface/cli/app/servers/profile.rb +88 -0
- data/lib/cloudflock/interface/cli/app/servers.rb +2 -0
- data/lib/cloudflock/interface/cli/console.rb +213 -0
- data/lib/cloudflock/interface/cli/opts/servers.rb +20 -0
- data/lib/cloudflock/interface/cli/opts.rb +87 -0
- data/lib/cloudflock/interface/cli.rb +15 -0
- data/lib/cloudflock/patch/fog.rb +113 -0
- data/lib/cloudflock/remote/ssh.rb +311 -0
- data/lib/cloudflock/target/servers/data/exceptions/base.txt +44 -0
- data/lib/cloudflock/target/servers/data/exceptions/platform/amazon.txt +10 -0
- data/lib/cloudflock/target/servers/data/exceptions/platform/debian.txt +0 -0
- data/lib/cloudflock/target/servers/data/exceptions/platform/redhat.txt +5 -0
- data/lib/cloudflock/target/servers/data/exceptions/platform/suse.txt +1 -0
- data/lib/cloudflock/target/servers/data/post-migration/chroot/base.txt +1 -0
- data/lib/cloudflock/target/servers/data/post-migration/chroot/platform/amazon.txt +19 -0
- data/lib/cloudflock/target/servers/data/post-migration/pre/base.txt +3 -0
- data/lib/cloudflock/target/servers/data/post-migration/pre/platform/amazon.txt +4 -0
- data/lib/cloudflock/target/servers/migrate.rb +466 -0
- data/lib/cloudflock/target/servers/platform/v1.rb +97 -0
- data/lib/cloudflock/target/servers/platform/v2.rb +93 -0
- data/lib/cloudflock/target/servers/platform.rb +133 -0
- data/lib/cloudflock/target/servers/profile.rb +394 -0
- data/lib/cloudflock/target/servers.rb +5 -0
- data/lib/cloudflock/version.rb +3 -0
- data/lib/cloudflock.rb +10 -0
- metadata +128 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'cpe'
|
2
|
+
require 'cloudflock'
|
3
|
+
|
4
|
+
# Public: Serves as a small class to easily map host specifications to Image
|
5
|
+
# and Flavor IDs in Rackspace Cloud.
|
6
|
+
#
|
7
|
+
# Examples
|
8
|
+
#
|
9
|
+
# # Build platform data for a given CPE object
|
10
|
+
# platform = Platform.new(cpe)
|
11
|
+
# platform.image_id
|
12
|
+
# # => Fixnum
|
13
|
+
class CloudFlock::Target::Servers::Platform
|
14
|
+
# Public: Gets/sets whether the target platform will be managed.
|
15
|
+
attr_accessor :managed
|
16
|
+
# Public: Gets/sets whether the target platform will use Rack Connect.
|
17
|
+
attr_accessor :rack_connect
|
18
|
+
|
19
|
+
# Public: Initialize the Platform object.
|
20
|
+
#
|
21
|
+
# cpe - CPE object from which to generate platform object.
|
22
|
+
#
|
23
|
+
# Raises ArgumentError if anything but a CPE object was given.
|
24
|
+
# Raises KeyError if the CPE object doesn't have a vendor or version defined.
|
25
|
+
def initialize(cpe)
|
26
|
+
raise ArgumentError unless cpe.kind_of?(CPE)
|
27
|
+
raise KeyError if cpe.vendor.nil? or cpe.version.nil?
|
28
|
+
|
29
|
+
@cpe = cpe
|
30
|
+
@distro = cpe.vendor
|
31
|
+
@product = cpe.product
|
32
|
+
@version = cpe.version
|
33
|
+
@managed = false
|
34
|
+
@rack_connect = false
|
35
|
+
|
36
|
+
build_maps
|
37
|
+
end
|
38
|
+
|
39
|
+
# Public: Generate a String of the platform's name/version suitable for
|
40
|
+
# display
|
41
|
+
#
|
42
|
+
# Returns a String describing the Platform
|
43
|
+
def to_s
|
44
|
+
"#{@distro.capitalize} #{@product.gsub(/_/, ' ').capitalize} #{@version}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public: Return the Image ID to be used based on whether the account is
|
48
|
+
# managed, and the platform used
|
49
|
+
#
|
50
|
+
# Returns the Image ID corresponding to the Platform object as a String
|
51
|
+
def image
|
52
|
+
[:MANAGED_MAP, :UNMANAGED_MAP].each do |map|
|
53
|
+
unless self.class.const_defined?(map)
|
54
|
+
raise MapUndefined, "Const #{map} is undefined; maps appear unbuilt"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
map = @managed ? self.class::MANAGED_MAP : self.class::UNMANAGED_MAP
|
59
|
+
distro = @distro.downcase.to_sym
|
60
|
+
|
61
|
+
unless map[distro].nil?
|
62
|
+
return map[distro][@version] unless map[distro][@version].nil?
|
63
|
+
return map[distro]["*"] unless map[distro]["*"].nil?
|
64
|
+
end
|
65
|
+
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# Public: Iterate through TARGET_LIST until a suitably large flavor_id is
|
70
|
+
# found, then return the appropriate index. If no entry can be found, raise
|
71
|
+
# ValueError.
|
72
|
+
#
|
73
|
+
# symbol - A Symbol referencing the search target in TARGET_LIST.
|
74
|
+
# value - A Fixnum containing the amount of memory or disk space required.
|
75
|
+
#
|
76
|
+
# Returns a Fixnum referencing the TARGET_LIST index.
|
77
|
+
# Raises ValueError if no symbol describes an appropriate target.
|
78
|
+
def get_target_by_symbol(symbol, value)
|
79
|
+
unless self.class.const_defined?(:FLAVOR_LIST)
|
80
|
+
raise MapUndefined, "FLAVOR_LIST is undefined; maps appear unbuild."
|
81
|
+
end
|
82
|
+
|
83
|
+
self.class::FLAVOR_LIST.each_with_index do |target, idx|
|
84
|
+
if target[symbol] > value
|
85
|
+
return idx
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
raise ValueError, "Unable to find a flavor matching #{symbol} #{value}"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Internal: Build image and flavor maps
|
93
|
+
#
|
94
|
+
# Returns nothing
|
95
|
+
def build_maps
|
96
|
+
build_image_maps
|
97
|
+
build_flavor_maps
|
98
|
+
end
|
99
|
+
|
100
|
+
# Public: Give a recommendation for a Flavor ID and an Image ID which should
|
101
|
+
# suffice for a migration target host.
|
102
|
+
#
|
103
|
+
# args - Hash containing information on which to base the recommendation:
|
104
|
+
# :memory - Hash containing memory information:
|
105
|
+
# :total - Total amount of memory allocated to the host
|
106
|
+
# profiled.
|
107
|
+
# :mem_used - Amount of RAM in use at the time of
|
108
|
+
# profiling.
|
109
|
+
# :swapping? - Boolean denoting whether the host was
|
110
|
+
# swapping at the time of profiling.
|
111
|
+
# :disk - Fixnum containing the amount of disk which appears to be
|
112
|
+
# in use at the time of profiling.
|
113
|
+
#
|
114
|
+
# Returns a Hash containing the Flavor ID and a String containing the
|
115
|
+
# reasoning for the decision.
|
116
|
+
def build_recommendation(args)
|
117
|
+
recommendation = {}
|
118
|
+
target_mem = get_target_by_symbol(:mem, args[:memory][:mem_used])
|
119
|
+
target_mem += 1 if args[:memory][:swapping?]
|
120
|
+
|
121
|
+
target_disk = get_target_by_symbol(:hdd, args[:disk])
|
122
|
+
|
123
|
+
if target_mem >= target_disk
|
124
|
+
recommendation[:flavor] = target_mem
|
125
|
+
recommendation[:flavor_reason] = "RAM usage"
|
126
|
+
else
|
127
|
+
recommendation[:flavor] = target_disk
|
128
|
+
recommendation[:flavor_reason] = "Disk usage"
|
129
|
+
end
|
130
|
+
|
131
|
+
recommendation
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,394 @@
|
|
1
|
+
require 'cloudflock/remote/ssh'
|
2
|
+
require 'cpe'
|
3
|
+
|
4
|
+
# Public: Provides methods to create a profile for a given host, mapping it to
|
5
|
+
# available public cloud offerings, and reference data gathered during this
|
6
|
+
# process.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# # Generate a profile from a shell already logged in to a remote host
|
11
|
+
# profile = Profile.new(ssh_object)
|
12
|
+
# profile.build
|
13
|
+
#
|
14
|
+
# # Only determine the memory and I/O statistics for a host
|
15
|
+
# profile = Profile.new(ssh_object)
|
16
|
+
# profile.determine_memory
|
17
|
+
# profile.determine_io
|
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")
|
61
|
+
|
62
|
+
begin
|
63
|
+
cpe = CPE.parse(release)
|
64
|
+
cpe.version.gsub!(/[^0-9.]/, '')
|
65
|
+
@info[:cpe] = cpe
|
66
|
+
return
|
67
|
+
rescue ArgumentError
|
68
|
+
cpe = CPE.new(part: CPE::OS, product: "linux")
|
69
|
+
end
|
70
|
+
|
71
|
+
issue = @shell.query("ISSUE", "cat /etc/issue")
|
72
|
+
|
73
|
+
case issue
|
74
|
+
when /Arch/
|
75
|
+
cpe.vendor = "Arch"
|
76
|
+
when /CentOS/
|
77
|
+
cpe.vendor = "CentOS"
|
78
|
+
issue.gsub!(/\.\d.*$/, '')
|
79
|
+
when /Debian/
|
80
|
+
cpe.vendor = "Debian"
|
81
|
+
issue.gsub!(/\.\d.*$/, '')
|
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"
|
93
|
+
end
|
94
|
+
|
95
|
+
cpe.version = version_number(issue)
|
96
|
+
|
97
|
+
@info[:cpe] = cpe
|
98
|
+
end
|
99
|
+
|
100
|
+
# Public: Determine the architecture of the target host and assign it to
|
101
|
+
# @info[:arch].
|
102
|
+
#
|
103
|
+
# Returns nothing.
|
104
|
+
def determine_arch
|
105
|
+
uname = @shell.query("UNAME", "uname -m")
|
106
|
+
case uname
|
107
|
+
when /x86_64/
|
108
|
+
@info[:arch] = 'x86_64'
|
109
|
+
when /i\d86/
|
110
|
+
@info[:arch] = 'i386'
|
111
|
+
else
|
112
|
+
@info[:arch] = "Unknown"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Public: Determine the hostname of the target host and assign it to
|
117
|
+
# @info[:hostname]
|
118
|
+
#
|
119
|
+
# Returns nothing.
|
120
|
+
def determine_hostname
|
121
|
+
@info[:hostname] = @shell.query("HOST", "hostname")
|
122
|
+
end
|
123
|
+
|
124
|
+
# Public: Determine the available and total memory on the target host as
|
125
|
+
# well as historical usage via sar(1), if possible. Assign these to
|
126
|
+
# @info[:memory] and @info[:memory_hist], respectively.
|
127
|
+
#
|
128
|
+
# Returns nothing.
|
129
|
+
def determine_memory
|
130
|
+
result = {}
|
131
|
+
|
132
|
+
free = %w{free -m |awk '$1 ~ /Mem/ {print $2, $2-$6-$7}; $1 ~ /Swap/
|
133
|
+
{print $3}'|xargs}.join(' ')
|
134
|
+
mem = @shell.query("MEMORY", free)
|
135
|
+
total, used, swap = mem.split(/\s+/)
|
136
|
+
|
137
|
+
result[:total] = total.to_i
|
138
|
+
result[:mem_used] = used.to_i
|
139
|
+
result[:swap_used] = swap.to_i
|
140
|
+
result[:swapping?] = swap.to_i > 0
|
141
|
+
@info[:memory] = result
|
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
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
@info[:memory_hist] = result
|
163
|
+
end
|
164
|
+
|
165
|
+
# Public: Determine the number of CPUs present on the target host and the
|
166
|
+
# speed of the processors. Assign these to @info[:cpu][:count] and
|
167
|
+
# @info[:cpu][:speed] respectively.
|
168
|
+
#
|
169
|
+
# Returns nothing.
|
170
|
+
def determine_cpu
|
171
|
+
count_command = 'cat /proc/cpuinfo|grep "^processor\\s*: [0-9]"|wc -l'
|
172
|
+
speed_command = 'cat /proc/cpuinfo|grep "MHz"|head -1'
|
173
|
+
cpus = {}
|
174
|
+
cpus[:count] = @shell.query("CPU", count_command).to_i
|
175
|
+
cpus[:speed] = @shell.query("MHZ", speed_command).gsub(/.*: /, '').to_i
|
176
|
+
@info[:cpu] = cpus
|
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 => []}
|
198
|
+
|
199
|
+
ip_command = %w{/sbin/ifconfig | grep 'inet addr' | egrep -v ':127' | sed
|
200
|
+
-e 's/.*addr:\([0-9.]*\) .*/\1/'}.join(' ')
|
201
|
+
ifconfig = @shell.query("IP_CONFIG", ip_command)
|
202
|
+
|
203
|
+
ifconfig.each_line do |ip|
|
204
|
+
ip.strip!
|
205
|
+
ips[rfc1918?(ip)] << ip
|
206
|
+
end
|
207
|
+
|
208
|
+
@info[:ip] = ips
|
209
|
+
end
|
210
|
+
|
211
|
+
# Public: Determine amount of historical I/O usage via sysstat and set it to
|
212
|
+
# @info[:io].
|
213
|
+
#
|
214
|
+
# Returns nothing.
|
215
|
+
def determine_io
|
216
|
+
io = {}
|
217
|
+
|
218
|
+
iostat = @shell.query("IOSTAT", "iostat -c | sed -n 4p | awk '{print $4}'")
|
219
|
+
io[:wait] = iostat.to_f
|
220
|
+
|
221
|
+
up = @shell.query("UPTIME", "uptime | sed -e 's/.*up\\([^,]*\\),.*/\\1/'")
|
222
|
+
io[:uptime] = up.chomp
|
223
|
+
|
224
|
+
@info[:io] = io
|
225
|
+
end
|
226
|
+
|
227
|
+
# Public: Determine the web server used on the host, and attempt to enumerate
|
228
|
+
# domain names configured on the server for both non-SSL and SSL; set this
|
229
|
+
# information to @info[:web]. Presently only Apache is supported.
|
230
|
+
#
|
231
|
+
# Returns nothing.
|
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
|
253
|
+
end
|
254
|
+
|
255
|
+
@info[:web] = web
|
256
|
+
end
|
257
|
+
|
258
|
+
# Public: Determine the amount of disk usage attributable to databases, as
|
259
|
+
# well as database count, and set this to @info[:database]. Currently
|
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)
|
268
|
+
|
269
|
+
mysql_size = "du -s /var/lib/mysql 2>/dev/null | awk '{print $1}'"
|
270
|
+
db[:size] = @shell.query("DB_MYSQL_SIZE", mysql_size)
|
271
|
+
|
272
|
+
db[:count] = db[:count].to_i
|
273
|
+
db[:size] = db[:size].to_i
|
274
|
+
|
275
|
+
@info[:db] = db
|
276
|
+
end
|
277
|
+
|
278
|
+
# Public: Gather information about the currently installed libc, ruby, perl,
|
279
|
+
# python and php versions on the host, then set these values to @info[:lib].
|
280
|
+
#
|
281
|
+
# Returns nothing.
|
282
|
+
def determine_lib
|
283
|
+
lib = {}
|
284
|
+
|
285
|
+
libc_command = %w{ls -al `find /lib /usr/lib -name 'libc.so*' | head -1` |
|
286
|
+
sed 's/.*-> //'}.join(' ')
|
287
|
+
lib[:libc] = @shell.query("LIBC", libc_command)
|
288
|
+
lib[:libc].gsub!(/^.*-|\.so$/, '')
|
289
|
+
|
290
|
+
lib[:perl] = @shell.query("PERL", "perl -e 'print $^V;'")
|
291
|
+
lib[:perl] = lib[:perl].gsub(/^v([0-9.]*).*/, '\1')
|
292
|
+
|
293
|
+
python_command = "python -c 'import sys; print sys.version' 2>/dev/null"
|
294
|
+
lib[:python] = @shell.query("PYTHON", python_command)
|
295
|
+
lib[:python] = lib[:python].gsub(/^([0-9.]*).*/m, '\1')
|
296
|
+
|
297
|
+
ruby_command = "ruby -e 'print RUBY_VERSION' 2>/dev/null"
|
298
|
+
lib[:ruby] = @shell.query("RUBY", ruby_command)
|
299
|
+
|
300
|
+
lib[:php] = @shell.query("PHP_VER", "php -v 2>/dev/null | head -1")
|
301
|
+
lib[:php] = lib[:php].gsub(/^PHP ([0-9.]*).*/, '\1')
|
302
|
+
|
303
|
+
@info[:lib] = lib
|
304
|
+
end
|
305
|
+
|
306
|
+
# Public: Check for the existence of rsync(1) on the host. Set @info[:rsync]
|
307
|
+
# accordingly.
|
308
|
+
#
|
309
|
+
# Returns nothing.
|
310
|
+
def determine_rsync
|
311
|
+
rsync_command = %w{which rsync 2>/dev/null || ([ -f
|
312
|
+
/root/.rackspace/rsync ] && printf
|
313
|
+
'/root/.rackspace/rsync') || printf
|
314
|
+
'NONE'}.join(' ')
|
315
|
+
|
316
|
+
rsync = @shell.query("RSYNC", rsync_command)
|
317
|
+
|
318
|
+
@info[:rsync] = (rsync =~ /NONE/).nil? ? rsync : false
|
319
|
+
end
|
320
|
+
|
321
|
+
# Public: Check the process listing and store it in
|
322
|
+
#
|
323
|
+
# Returns nothing.
|
324
|
+
def determine_processes
|
325
|
+
ps_command = 'ps aux'
|
326
|
+
|
327
|
+
processes = @shell.query("PS_LIST", ps_command)
|
328
|
+
@info[:processes] = processes.gsub(/\r/, '').split(/\n/)
|
329
|
+
|
330
|
+
unless @info[:processes].grep(/psa/i).empty?
|
331
|
+
@warnings << "Server likely to be running Plesk"
|
332
|
+
end
|
333
|
+
unless @info[:processes].grep(/cpanellogd/i).empty?
|
334
|
+
@warnings << "Server likely to be running cPanel"
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# Public: Simplify access to @info.
|
339
|
+
#
|
340
|
+
# key - Key to check in @info.
|
341
|
+
#
|
342
|
+
# Return value contained in @info by key.
|
343
|
+
def [](key)
|
344
|
+
@info[key]
|
345
|
+
end
|
346
|
+
|
347
|
+
# Public: Allow access to the list of keys extant in @info.
|
348
|
+
#
|
349
|
+
# Return an Array of keys present in @info.
|
350
|
+
def keys
|
351
|
+
@info.keys
|
352
|
+
end
|
353
|
+
|
354
|
+
# Public: Return server information and warnings as a Hash. Useful for
|
355
|
+
# calling Hash#merge.
|
356
|
+
#
|
357
|
+
# Return info Hash.
|
358
|
+
def to_hash
|
359
|
+
@info.merge({warnings: @warnings})
|
360
|
+
end
|
361
|
+
|
362
|
+
# Internal: Deconstruct the version String provided in order to strip out
|
363
|
+
# extraneous data before and after the version number. Version number
|
364
|
+
# strings are defined as beginning with a digit, ending with a digit, and
|
365
|
+
# containing nothing but digits and at most one decimal point.
|
366
|
+
#
|
367
|
+
# version - A String containing version number of the OS on the target host.
|
368
|
+
#
|
369
|
+
# Returns a String containing the parsed version string.
|
370
|
+
def version_number(version)
|
371
|
+
if version =~ /\d/
|
372
|
+
version.gsub(/^[^\d]*/, '').gsub(/[^\d]*$/, '').gsub(/(\d*\.\d*).*/, '\1')
|
373
|
+
else
|
374
|
+
"-"
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
# Internal: Determine whether a given IP resides in a block designated as
|
379
|
+
# private by RFC1918.
|
380
|
+
#
|
381
|
+
# ip - A String containing an IP address.
|
382
|
+
#
|
383
|
+
# Returns :private or :public Symbol based on whether the IP is private.
|
384
|
+
def rfc1918?(ip)
|
385
|
+
octets = ip.split /\./
|
386
|
+
if octets[0] == "10" || (octets[0] == "192" && octets[1] == "168")
|
387
|
+
return :private
|
388
|
+
elsif octets[0] == "172" && octets[1].to_i >=16 && octets[1].to_i <= 31
|
389
|
+
return :private
|
390
|
+
end
|
391
|
+
|
392
|
+
:public
|
393
|
+
end
|
394
|
+
end
|
data/lib/cloudflock.rb
ADDED
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudflock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Wuest
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fog
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: expectr
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: cpe
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: CloudFlock is a library and toolchain focused on migration
|
63
|
+
email: chris@chriswuest.com
|
64
|
+
executables:
|
65
|
+
- flock
|
66
|
+
- flock-profile
|
67
|
+
- flock-servers
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- lib/cloudflock.rb
|
72
|
+
- lib/cloudflock/error.rb
|
73
|
+
- lib/cloudflock/interface/cli.rb
|
74
|
+
- lib/cloudflock/interface/cli/app/common/servers.rb
|
75
|
+
- lib/cloudflock/interface/cli/app/servers.rb
|
76
|
+
- lib/cloudflock/interface/cli/app/servers/migrate.rb
|
77
|
+
- lib/cloudflock/interface/cli/app/servers/profile.rb
|
78
|
+
- lib/cloudflock/interface/cli/console.rb
|
79
|
+
- lib/cloudflock/interface/cli/opts.rb
|
80
|
+
- lib/cloudflock/interface/cli/opts/servers.rb
|
81
|
+
- lib/cloudflock/patch/fog.rb
|
82
|
+
- lib/cloudflock/remote/ssh.rb
|
83
|
+
- lib/cloudflock/target/servers.rb
|
84
|
+
- lib/cloudflock/target/servers/data/exceptions/base.txt
|
85
|
+
- lib/cloudflock/target/servers/data/exceptions/platform/amazon.txt
|
86
|
+
- lib/cloudflock/target/servers/data/exceptions/platform/debian.txt
|
87
|
+
- lib/cloudflock/target/servers/data/exceptions/platform/redhat.txt
|
88
|
+
- lib/cloudflock/target/servers/data/exceptions/platform/suse.txt
|
89
|
+
- lib/cloudflock/target/servers/data/post-migration/chroot/base.txt
|
90
|
+
- lib/cloudflock/target/servers/data/post-migration/chroot/platform/amazon.txt
|
91
|
+
- lib/cloudflock/target/servers/data/post-migration/pre/base.txt
|
92
|
+
- lib/cloudflock/target/servers/data/post-migration/pre/platform/amazon.txt
|
93
|
+
- lib/cloudflock/target/servers/migrate.rb
|
94
|
+
- lib/cloudflock/target/servers/platform.rb
|
95
|
+
- lib/cloudflock/target/servers/platform/v1.rb
|
96
|
+
- lib/cloudflock/target/servers/platform/v2.rb
|
97
|
+
- lib/cloudflock/target/servers/profile.rb
|
98
|
+
- lib/cloudflock/version.rb
|
99
|
+
- bin/flock
|
100
|
+
- bin/flock-profile
|
101
|
+
- bin/flock-servers
|
102
|
+
- bin/flock.default
|
103
|
+
homepage: http://github.com/cwuest/cloudflock
|
104
|
+
licenses:
|
105
|
+
- Apache 2.0
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 1.8.25
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Server migration automation
|
128
|
+
test_files: []
|