cloudflock 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +15 -0
  2. data/bin/cloudflock +7 -1
  3. data/bin/cloudflock-files +2 -14
  4. data/bin/cloudflock-profile +3 -15
  5. data/bin/cloudflock-servers +3 -22
  6. data/bin/cloudflock.default +3 -22
  7. data/lib/cloudflock/app/common/cleanup/unix.rb +23 -0
  8. data/lib/cloudflock/app/common/cleanup.rb +107 -0
  9. data/lib/cloudflock/app/common/exclusions/unix/centos.rb +18 -0
  10. data/lib/cloudflock/app/common/exclusions/unix/redhat.rb +18 -0
  11. data/lib/cloudflock/app/common/exclusions/unix.rb +58 -0
  12. data/lib/cloudflock/app/common/exclusions.rb +57 -0
  13. data/lib/cloudflock/app/common/platform_action.rb +59 -0
  14. data/lib/cloudflock/app/common/rackspace.rb +63 -0
  15. data/lib/cloudflock/app/common/servers.rb +673 -0
  16. data/lib/cloudflock/app/files-migrate.rb +246 -0
  17. data/lib/cloudflock/app/server-migrate.rb +327 -0
  18. data/lib/cloudflock/app/server-profile.rb +130 -0
  19. data/lib/cloudflock/app.rb +87 -0
  20. data/lib/cloudflock/error.rb +6 -19
  21. data/lib/cloudflock/errstr.rb +31 -0
  22. data/lib/cloudflock/remote/files.rb +82 -22
  23. data/lib/cloudflock/remote/ssh.rb +234 -278
  24. data/lib/cloudflock/target/servers/platform.rb +92 -115
  25. data/lib/cloudflock/target/servers/profile.rb +331 -340
  26. data/lib/cloudflock/task/server-profile.rb +651 -0
  27. data/lib/cloudflock.rb +6 -8
  28. metadata +49 -68
  29. data/lib/cloudflock/interface/cli/app/common/servers.rb +0 -128
  30. data/lib/cloudflock/interface/cli/app/files.rb +0 -179
  31. data/lib/cloudflock/interface/cli/app/servers/migrate.rb +0 -491
  32. data/lib/cloudflock/interface/cli/app/servers/profile.rb +0 -88
  33. data/lib/cloudflock/interface/cli/app/servers.rb +0 -2
  34. data/lib/cloudflock/interface/cli/console.rb +0 -213
  35. data/lib/cloudflock/interface/cli/opts/servers.rb +0 -20
  36. data/lib/cloudflock/interface/cli/opts.rb +0 -87
  37. data/lib/cloudflock/interface/cli.rb +0 -15
  38. data/lib/cloudflock/target/servers/data/exceptions/base.txt +0 -44
  39. data/lib/cloudflock/target/servers/data/exceptions/platform/amazon.txt +0 -10
  40. data/lib/cloudflock/target/servers/data/exceptions/platform/centos.txt +0 -7
  41. data/lib/cloudflock/target/servers/data/exceptions/platform/debian.txt +0 -0
  42. data/lib/cloudflock/target/servers/data/exceptions/platform/redhat.txt +0 -7
  43. data/lib/cloudflock/target/servers/data/exceptions/platform/suse.txt +0 -1
  44. data/lib/cloudflock/target/servers/data/post-migration/chroot/base.txt +0 -1
  45. data/lib/cloudflock/target/servers/data/post-migration/chroot/platform/amazon.txt +0 -19
  46. data/lib/cloudflock/target/servers/data/post-migration/pre/base.txt +0 -3
  47. data/lib/cloudflock/target/servers/data/post-migration/pre/platform/amazon.txt +0 -4
  48. data/lib/cloudflock/target/servers/migrate.rb +0 -466
  49. data/lib/cloudflock/target/servers/platform/v1.rb +0 -97
  50. data/lib/cloudflock/target/servers/platform/v2.rb +0 -93
  51. data/lib/cloudflock/target/servers.rb +0 -5
  52. data/lib/cloudflock/version.rb +0 -3
@@ -1,491 +0,0 @@
1
- require 'fog'
2
- require 'socket'
3
- require 'tempfile'
4
- require 'cloudflock/target/servers'
5
- require 'cloudflock/interface/cli/app/common/servers'
6
-
7
- # Public: The Servers::Migrate app provides the interface to Servers migrations
8
- # (primarily targeting Managed/Unmanaged Rackspace First-gen and Open Cloud,
9
- # but other migrations are possible) on the CLI.
10
- class CloudFlock::Interface::CLI::App::Servers::Migrate
11
- include CloudFlock::Interface::CLI::App::Common::Servers
12
- CLI = CloudFlock::Interface::CLI::Console
13
-
14
- # Public: Begin Servers migration on the command line
15
- #
16
- # opts - Hash containing options mappings.
17
- def initialize(opts)
18
- opencloud = (opts[:function] == :opencloud)
19
-
20
- resume = opts[:resume]
21
- source_host_def = define_source(opts[:config])
22
- source_host_ssh = CLI.spinner("Logging in to #{source_host_def[:host]}") do
23
- host_login(source_host_def)
24
- end
25
-
26
- source_profile = CLI.spinner("Checking source host") do
27
- profile = Profile.new(source_host_ssh)
28
- profile.build
29
- profile
30
- end
31
-
32
- if opencloud
33
- target_platform = Platform::V2
34
- else
35
- target_platform = Platform::V1
36
- end
37
- platform = target_platform.new(source_profile[:cpe])
38
- build_target = platform.build_recommendation(source_profile)
39
- flavor_list = target_platform::FLAVOR_LIST
40
- default_target = flavor_list[build_target[:flavor]]
41
-
42
- # Generate and display a brief summary of the server Platform/Profile
43
- os_tag = source_profile[:cpe].vendor == "Unknown" ? CLI.red : CLI.blue
44
- ram_qty = default_target[:mem]
45
- hdd_qty = default_target[:hdd]
46
- decision_reason = "#{CLI.bold}#{build_target[:flavor_reason]}#{CLI.reset}"
47
-
48
- puts "OS: #{CLI.bold}#{os_tag}#{platform}#{CLI.reset}"
49
- puts "---"
50
- puts "Recommended server:"
51
- puts "RAM: #{CLI.bold} % 6d MiB#{CLI.reset}" % ram_qty
52
- puts "HDD: #{CLI.bold} % 7d GB#{CLI.reset}" % hdd_qty
53
- puts "The reason for this decision is: #{decision_reason}"
54
- puts "---"
55
- unless source_profile.warnings.empty?
56
- print CLI.red + CLI.bold
57
- source_profile.warnings.each { |warning| puts warning }
58
- print CLI.reset
59
- puts "---"
60
- end
61
-
62
- if resume
63
- destination_host_def = define_destination
64
- migration_exclusions = determine_exclusions(source_profile[:cpe])
65
- platform.managed = CLI.prompt_yn("Managed service level? (Y/N)",
66
- default_answer: "Y")
67
- platform.rack_connect = CLI.prompt_yn("Rack Connected? (Y/N)",
68
- default_answer: "N")
69
- else
70
- api = {}
71
- api[:version] = opencloud ? :v2 : :v1
72
-
73
- proceed = CLI.prompt_yn("Spin up this server? (Y/N)", default_answer: "Y")
74
- if proceed
75
- api[:flavor] = default_target[:id]
76
- else
77
- puts CLI.build_grid(flavor_list,
78
- {id: "ID", mem: "RAM (MiB)", hdd: "HDD (GB)" })
79
- api[:flavor] = CLI.prompt("Flavor ID",
80
- default_answer: default_target[:id])
81
- api[:flavor] = api[:flavor].to_i
82
- end
83
-
84
- migration_exclusions = determine_exclusions(source_profile[:cpe])
85
- platform.managed = CLI.prompt_yn("Managed service level? (Y/N)",
86
- default_answer: "Y")
87
- platform.rack_connect = CLI.prompt_yn("Rack Connected? (Y/N)",
88
- default_answer: "N")
89
-
90
- # Warn against Rack Connect
91
- if platform.rack_connect
92
- puts "#{CLI.bold}#{CLI.red}*** Rack Connect servers might not " +
93
- "provision properly when spun up from the API! Resume " +
94
- "recommended!#{CLI.reset}"
95
- sleep 5
96
- end
97
-
98
-
99
- # Check to make sure we have a valid flavor ID
100
- exit 0 if api[:flavor] == 0 or flavor_list[api[:flavor]-1].nil?
101
-
102
- # Build our API call
103
- api[:hostname] = CLI.prompt("New Server Name",
104
- default_answer: source_profile[:hostname])
105
-
106
- # OpenCloud only supports US migrations presently
107
- if opts[:function] == :opencloud
108
- api[:region] = CLI.prompt("Region (dfw, ord)", default_answer: "dfw",
109
- valid_answers: ["ord", "dfw"])
110
- else
111
- api[:region] = :dfw
112
- end
113
-
114
- api[:username] = CLI.prompt("RS Cloud Username")
115
- api[:api_key] = CLI.prompt("RS Cloud API key")
116
-
117
- # Name cannot have any special characters in it
118
- api[:hostname].gsub!(/[^A-Za-z0-9.]/, '-')
119
-
120
- rack_api = Fog::Compute.new(provider: 'rackspace',
121
- rackspace_username: api[:username],
122
- rackspace_api_key: api[:api_key],
123
- rackspace_region: api[:region],
124
- version: api[:version])
125
-
126
- # Send API call
127
- new_server = CLI.spinner("Spinning up new server: #{api[:hostname]}") do
128
- rack_api.servers::create(name: api[:hostname],
129
- image_id: platform.image,
130
- flavor_id: api[:flavor])
131
-
132
- end
133
-
134
- # Set the destination host address
135
- destination_host_def = {}
136
- CLI.spinner("Obtaining information for new instance") do
137
- # Obtain the administrative pass for the new host.
138
- destination_host_def[:password] = new_server.password
139
- server_id = new_server.id
140
-
141
- until new_server.state == 'ACTIVE'
142
- sleep 30
143
- begin
144
- new_server.update
145
- rescue NoMethodError
146
- new_server.reload
147
- end
148
- end
149
-
150
- if opencloud
151
- dest_host = new_server.addresses["public"].select do |e|
152
- e["version"] == 4
153
- end
154
- destination_host_def[:host] = dest_host[0]["addr"]
155
- else
156
- destination_host_def[:host] = new_server.addresses["public"][0]
157
- end
158
- end
159
-
160
- # If we're working within the Managed service level, ensure that Chef
161
- # has finished successfully
162
- if platform.managed
163
- r = 0
164
- destination_host_ssh = destination_login(destination_host_def)
165
-
166
- begin
167
- message =
168
- finished = CLI.spinner("Waiting for Chef to finish") do
169
- # Sleep 180 seconds before trying
170
- sleep 180
171
- Migrate.setup_managed(destination_host_ssh)
172
- end
173
- unless finished
174
- panic = "#{CLI.bold}#{CLI.red}*** MGC Cloud Scripts appear to " +
175
- "have failed to run in a reasonable amount of time." +
176
- "#{CLI.reset}"
177
- puts panic
178
- exit unless CLI.prompt_yn("Continue? (Y/N)", default_answer: "Y")
179
- end
180
- destination_host_ssh.logout!
181
- rescue
182
- panic = "#{CLI.bold}#{CLI.red}*** Unable to communicate with the " +
183
- "destination host. Bailing out.#{CLI.reset}"
184
- puts panic
185
- raise
186
- end
187
- end
188
-
189
- if opts[:function] == :opencloud
190
- host = destination_host_def[:host]
191
- CLI.spinner("Putting #{host} into rescue mode") do
192
- new_server.rescue
193
- destination_host_def[:password] = new_server.password
194
- new_server.update
195
- end
196
- else
197
- pass_prompt = "Please put #{api[:hostname]} into rescue mode and " +
198
- "give password"
199
- destination_host_def[:password] = CLI.prompt(pass_prompt)
200
- end
201
-
202
- CLI.spinner "Letting rescue mode come up..." do
203
- until new_server.state == 'RESCUE'
204
- sleep 30
205
- begin
206
- new_server.update
207
- rescue NoMethodError
208
- sleep 60
209
- new_server.reload
210
- end
211
- end
212
- end
213
-
214
- Thread.new do
215
- continue = false
216
- until continue
217
- r = 0
218
- message = "Checking for SSH on #{destination_host_def[:host]}"
219
- ssh_command = "ssh #{SSH::SSH_ARGUMENTS} " +
220
- "root@#{destination_host_def[:host]}"
221
- continue = CLI.spinner(message) do
222
- begin
223
- sleep 20
224
- ssh_expect = Expectr.new(ssh_command, flush_buffer: false)
225
- ssh_expect.expect("password")
226
- rescue
227
- retry if (r+=1) < 10
228
- raise
229
- end
230
- end
231
- end
232
- end.join
233
- end
234
-
235
- destination_host_ssh = destination_login(destination_host_def)
236
-
237
- unless destination_host_def[:pre_steps] == false
238
- # Attempt to set up the source host 5 times. If there is a failure,
239
- # sleep for 60 seconds before retrying.
240
- r = 0
241
- begin
242
- message = "Setting up source host (attempt #{r + 1}/5)"
243
- pubkey = CLI.spinner(message) do
244
- begin
245
- message.gsub!(/\d\/5/, "#{r + 1}/5")
246
- sleep 60 unless r == 0
247
- Migrate.setup_source(source_host_ssh, migration_exclusions)
248
- rescue
249
- retry if (r += 1) < 5
250
- raise
251
- end
252
- end
253
- rescue
254
- panic = "#{CLI.bold}#{CLI.red}*** Unable to communicate with the " +
255
- "source host. Bailing out.#{CLI.reset}"
256
- puts panic
257
- raise
258
- end
259
-
260
- # Attempt to set up the destination host 5 times. If there is a
261
- # failure, sleep for 60 seconds before retrying.
262
- r = 0
263
- begin
264
- message = "Setting up destination host (attempt #{r + 1}/5)"
265
- CLI.spinner(message) do
266
- begin
267
- message.gsub!(/\d\/5/, "#{r + 1}/5")
268
- sleep 60 unless r == 0
269
- Migrate.setup_destination(destination_host_ssh, pubkey)
270
- rescue
271
- retry if (r += 1) < 5
272
- raise
273
- end
274
- end
275
- rescue
276
- panic = "#{CLI.bold}#{CLI.red}*** Unable to communicate with the " +
277
- "destination host. Bailing out.#{CLI.reset}"
278
- puts panic
279
- raise
280
- end
281
- end
282
-
283
- # Determine if Service Net can be used
284
- begin
285
- CLI.spinner "Checking for ServiceNet" do
286
- target_addr = Migrate.check_servicenet(source_host_ssh,
287
- destination_host_ssh)
288
- raise if target_addr.nil?
289
- destination_host_def[:target_addr] = target_addr
290
- end
291
- rescue
292
- destination_host_def[:target_addr] = destination_host_def[:host]
293
- end
294
-
295
- # Set rsync path and no timeout for the migration rsync
296
- destination_host_def[:timeout] = -1
297
- destination_host_def[:rsync] = source_profile[:rsync]
298
-
299
- # Kick off the migration proper
300
- if opts[:verbose]
301
- Migrate.migrate_server(source_host_ssh, destination_host_def)
302
- else
303
- CLI.spinner "Performing migration" do
304
- Migrate.migrate_server(source_host_ssh, destination_host_def)
305
- end
306
- end
307
-
308
- CLI.spinner "Logging out of source host" do
309
- source_host_ssh.logout!
310
- end
311
-
312
- CLI.spinner "Cleaning up destination host" do
313
- Migrate.clean_destination(destination_host_ssh, source_profile[:cpe])
314
- end
315
-
316
- ip_list = determine_ips(source_profile[:ip][:public])
317
- ip_list.each { |ip| remediate_ip_config(destination_host_ssh, ip, destination_host_def[:host]) }
318
-
319
- CLI.spinner "Logging out of destination host" do
320
- source_host_ssh.logout!
321
- end
322
-
323
- puts
324
- puts "#{CLI.bold}#{CLI.blue}*** Migration complete#{CLI.reset}\a"
325
- end
326
-
327
- # Internal: Ask whether or not to edit the default exclusion list for a given
328
- # platform, and facilitate the edit if so.
329
- #
330
- # cpe - CPE object for the host in question.
331
- #
332
- # Returns a String containing the exclusions.
333
- # Raises ArgumentError if cpe isn't a CPE object.
334
- def determine_exclusions(cpe)
335
- raise ArgumentError unless cpe.kind_of?(CPE)
336
-
337
- exclusion_string = Migrate.build_default_exclusions(cpe)
338
- alter = CLI.prompt_yn("Edit default exclusions list? (Y/N)",
339
- default_answer: "N")
340
-
341
- if alter
342
- tmp_file = Tempfile.new("exclude")
343
- tmp_file.write(exclusion_string)
344
- tmp_file.close
345
-
346
- # Allow for "other" editors
347
- if File.exists?("/usr/bin/editor")
348
- editor = "/usr/bin/editor"
349
- else
350
- editor = "vim"
351
- end
352
-
353
- system("#{editor} #{tmp_file.path}")
354
- tmp_file.open
355
- exclusion_string = tmp_file.read
356
- tmp_file.close
357
- tmp_file.unlink
358
- end
359
-
360
- exclusion_string
361
- end
362
-
363
- # Internal: Show the list of IPs detected and ascertain whether to perform
364
- # remediation of configuration files.
365
- #
366
- # ip_list - Array containing Strings containing IP addresses detected from
367
- # the source host.
368
- #
369
- # Returns an Array of Strings containing IPs to consider for remediation.
370
- # Raises an ArgumentError if ip_list is not an Array.
371
- def determine_ips(ip_list)
372
- unless ip_list.kind_of?(Array)
373
- raise ArgumentError, "Expected an Array, got a #{ip_list.class.name}"
374
- end
375
- return([]) if ip_list.empty?
376
-
377
- puts "IP Addresses detected for remediation:"
378
- puts ip_list
379
-
380
- if CLI.prompt_yn("Edit IP list? (Y/N)", default_answer: "N")
381
- tmp_file = Tempfile.new("ips")
382
- tmp_file.write(ip_list.join("\n"))
383
- tmp_file.close
384
-
385
- launch_editor(tmp_file.path)
386
- tmp_file.open
387
-
388
- ip_list = tmp_file.lines.select do |ip|
389
- begin
390
- Socket.getaddrinfo(ip, nil, nil, Socket::SOCK_STREAM)[0][3]
391
- rescue SocketError
392
- false
393
- end
394
- end
395
-
396
- tmp_file.close
397
- tmp_file.unlink
398
- end
399
-
400
- ip_list
401
- end
402
-
403
- # Internal: Find instances of a given IP in configuration files and
404
- # selectively replace them with an IP available on the target system.
405
- #
406
- # destination_shell - CloudFlock::Remote::SSH object connected to the
407
- # destination host.
408
- # source_ip - String containing an IP.
409
- # destination_ip - String containing primary IP detected for the host.
410
- #
411
- # Returns nothing.
412
- # Raises ArgumentError if source_ip is not a String.
413
- def remediate_ip_config(destination_shell, source_ip, destination_ip)
414
- unless destination_shell.kind_of?(CloudFlock::Remote::SSH)
415
- raise ArgumentError, "Expected an SSH session, got a " +
416
- "#{destination_shell.class.name}"
417
- end
418
- unless source_ip.kind_of?(String)
419
- raise ArgumentError, "Expected a String, got a #{source_ip.class.name}"
420
- end
421
- source_ip = Socket.getaddrinfo(source_ip, nil, nil,
422
- Socket::SOCK_STREAM)[0][3]
423
-
424
- grep_command = "grep -rl #{source_ip} /mnt/migration_target/etc " +
425
- "2>/dev/null | grep -v log"
426
- files = destination_shell.query("IP_CHECK", grep_command)
427
- unless files.strip.empty?
428
- tmp_file = Tempfile.new("filelist")
429
- tmp_file.write("Configuration files found for #{source_ip}:\n\n#{files}")
430
- tmp_file.close
431
- system("less -C #{tmp_file.path}")
432
- tmp_file.unlink
433
-
434
- proceed = CLI.prompt_yn("Replace #{source_ip} in these files? (Y/N)",
435
- default_answer: "Y")
436
- if proceed
437
- edit = false
438
- else
439
- edit = CLI.prompt_yn("Edit the list? (Y/N)", default: "Y")
440
- end
441
-
442
- if edit
443
- tmp_file = Tempfile.new("filelist")
444
- tmp_file.write("#{files}")
445
- tmp_file.close
446
- launch_editor(tmp_file.path)
447
- tmp_file.open
448
- files = tmp_file.read
449
- tmp_file.unlink
450
- proceed = true
451
- end
452
-
453
- if proceed
454
- replacement_ip = CLI.prompt("IP to replace #{source_ip}",
455
- default_answer: destination_ip)
456
- CLI.spinner("Remediating configuration files for #{source_ip}") do
457
- files.each_line do |file|
458
- file.strip!
459
- next if file.empty?
460
- file.gsub!(/'/, "\\'")
461
-
462
- sed_command = "sed -i 's/#{source_ip}/#{replacement_ip}/' '#{file}'"
463
- destination_shell.puts(sed_command)
464
- destination_shell.prompt
465
- end
466
- end
467
- end
468
- end
469
- end
470
-
471
- # Internal: Launch the user's editor to edit a file.
472
- #
473
- # path - String containing the path to the file to edit
474
- #
475
- # Returns nothing.
476
- # Raises Errno::ENOENT if the path does not point to an existing file.
477
- def launch_editor(path)
478
- unless File.exists?(path)
479
- raise Errno::ENOENT, "Unable to open #{path}"
480
- end
481
-
482
- # Allow for "other" editors
483
- if File.exists?("/usr/bin/editor")
484
- editor = "/usr/bin/editor"
485
- else
486
- editor = "vim"
487
- end
488
-
489
- system("#{editor} #{path}")
490
- end
491
- end
@@ -1,88 +0,0 @@
1
- require 'cloudflock/target/servers'
2
- require 'cloudflock/interface/cli/app/common/servers'
3
-
4
- # Public: The Profile class provides the interface to produces profiles
5
- # describing servers running Unix-like operating systems.
6
- class CloudFlock::Interface::CLI::App::Servers::Profile
7
- include CloudFlock::Interface::CLI::App::Common::Servers
8
- include CloudFlock::Target::Servers
9
- CLI = CloudFlock::Interface::CLI::Console
10
-
11
- # Public: Begin Servers migration on the command line
12
- #
13
- # opts - Hash containing options mappings.
14
- def initialize(opts)
15
- resume = opts[:resume]
16
- source_host_def = define_source(opts[:config])
17
- source_host_ssh = CLI.spinner("Logging in to #{source_host_def[:host]}") do
18
- host_login(source_host_def)
19
- end
20
-
21
- profile = CLI.spinner("Checking source host") do
22
- profile = Profile.new(source_host_ssh)
23
- profile.build
24
- profile
25
- end
26
- platform = Platform::V2.new(profile[:cpe])
27
-
28
- memory = profile[:memory]
29
- memory_percent = memory[:mem_used].to_f / memory[:total] * 100
30
- swapping = memory[:swapping?]
31
- ftag = "#{CLI.bold}%15s#{CLI.reset}:"
32
- hist_mem = profile[:memory_hist][:mem_used]
33
-
34
- puts
35
- puts "#{CLI.bold}System Information#{CLI.reset}"
36
- puts "#{ftag} #{platform} (#{profile[:cpe]})" % "OS"
37
- puts "#{ftag} #{profile[:arch]}" % "Arch"
38
- puts "#{ftag} #{profile[:hostname]}" % "Hostname"
39
- puts
40
-
41
- puts "#{CLI.bold}CPU Statistics#{CLI.reset}"
42
- puts "#{ftag} %d" % ["CPU Count", profile[:cpu][:count]]
43
- puts "#{ftag} %d MHz" % ["CPU Speed", profile[:cpu][:speed]]
44
- puts
45
-
46
- puts "#{CLI.bold}Memory Statistics#{CLI.reset}"
47
- puts "#{ftag} %d MiB" % ["Total RAM", memory[:total]]
48
- puts "#{ftag} %d MiB (%2.1f%%)" % ["RAM Used", memory[:mem_used],
49
- memory_percent]
50
- puts "#{ftag} %d MiB" % ["Swap Used", memory[:swap_used]] if swapping
51
- puts "#{ftag} %d%%" % ["Hist. RAM Used", hist_mem] unless hist_mem.nil?
52
- puts
53
-
54
- puts "#{CLI.bold}Hard Disk Statistics#{CLI.reset}"
55
- puts "#{ftag} %2.1f GB" % ["Disk Used", profile[:disk]]
56
- puts
57
-
58
- puts "#{CLI.bold}System Statistics#{CLI.reset}"
59
- puts "#{ftag} #{profile[:io][:uptime]}" % "Uptime"
60
- puts "#{ftag} #{profile[:io][:wait]}" % "I/O Wait"
61
- puts
62
-
63
- puts "#{CLI.bold}IP Information#{CLI.reset}"
64
- puts "#{ftag} #{profile[:ip][:public].join(', ')}" % "Public"
65
- puts "#{ftag} #{profile[:ip][:private].join(', ')}" % "Private"
66
- puts
67
-
68
- puts "#{CLI.bold}MySQL Databases#{CLI.reset}"
69
- puts "#{ftag} #{profile[:db][:count]}" % "Number"
70
- puts "#{ftag} #{profile[:db][:size]}" % "Total Size"
71
- puts
72
-
73
- puts "#{CLI.bold}Libraries#{CLI.reset}"
74
- puts "#{ftag} #{profile[:lib][:libc]}" % "LIBC"
75
- puts "#{ftag} #{profile[:lib][:perl]}" % "Perl"
76
- puts "#{ftag} #{profile[:lib][:python]}" % "Python"
77
- puts "#{ftag} #{profile[:lib][:ruby]}" % "Ruby"
78
- puts "#{ftag} #{profile[:lib][:php]}" % "PHP"
79
- unless profile.warnings.empty?
80
- puts
81
- print CLI.red + CLI.bold
82
- profile.warnings.each { |warning| puts warning }
83
- print CLI.reset
84
- end
85
-
86
- source_host_ssh.logout!
87
- end
88
- end
@@ -1,2 +0,0 @@
1
- require 'cloudflock/interface/cli'
2
- require 'cloudflock/interface/cli/app/common/servers'