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.
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'