greenhat 0.1.4

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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +64 -0
  3. data/bin/greenhat +12 -0
  4. data/lib/greenhat.rb +80 -0
  5. data/lib/greenhat/accessors/disk.rb +27 -0
  6. data/lib/greenhat/accessors/logs/production.rb +41 -0
  7. data/lib/greenhat/accessors/logs/sidekiq.rb +41 -0
  8. data/lib/greenhat/accessors/memory.rb +46 -0
  9. data/lib/greenhat/accessors/network.rb +8 -0
  10. data/lib/greenhat/accessors/process.rb +8 -0
  11. data/lib/greenhat/archive.rb +108 -0
  12. data/lib/greenhat/cli.rb +448 -0
  13. data/lib/greenhat/host.rb +182 -0
  14. data/lib/greenhat/logbot.rb +86 -0
  15. data/lib/greenhat/pry_helpers.rb +51 -0
  16. data/lib/greenhat/settings.rb +51 -0
  17. data/lib/greenhat/shell.rb +92 -0
  18. data/lib/greenhat/shell/cat.rb +125 -0
  19. data/lib/greenhat/shell/disk.rb +68 -0
  20. data/lib/greenhat/shell/faststats.rb +195 -0
  21. data/lib/greenhat/shell/gitlab.rb +45 -0
  22. data/lib/greenhat/shell/help.rb +15 -0
  23. data/lib/greenhat/shell/helper.rb +514 -0
  24. data/lib/greenhat/shell/log.rb +344 -0
  25. data/lib/greenhat/shell/memory.rb +31 -0
  26. data/lib/greenhat/shell/network.rb +12 -0
  27. data/lib/greenhat/shell/process.rb +12 -0
  28. data/lib/greenhat/shell/report.rb +319 -0
  29. data/lib/greenhat/thing.rb +121 -0
  30. data/lib/greenhat/thing/file_types.rb +705 -0
  31. data/lib/greenhat/thing/formatters/api_json.rb +34 -0
  32. data/lib/greenhat/thing/formatters/bracket_log.rb +44 -0
  33. data/lib/greenhat/thing/formatters/clean_raw.rb +23 -0
  34. data/lib/greenhat/thing/formatters/colon_split_strip.rb +12 -0
  35. data/lib/greenhat/thing/formatters/dotenv.rb +10 -0
  36. data/lib/greenhat/thing/formatters/format.rb +12 -0
  37. data/lib/greenhat/thing/formatters/free_m.rb +29 -0
  38. data/lib/greenhat/thing/formatters/gitlab_ctl_tail.rb +51 -0
  39. data/lib/greenhat/thing/formatters/gitlab_status.rb +26 -0
  40. data/lib/greenhat/thing/formatters/json.rb +63 -0
  41. data/lib/greenhat/thing/formatters/json_shellwords.rb +44 -0
  42. data/lib/greenhat/thing/formatters/multiline_json.rb +10 -0
  43. data/lib/greenhat/thing/formatters/raw.rb +18 -0
  44. data/lib/greenhat/thing/formatters/shellwords.rb +23 -0
  45. data/lib/greenhat/thing/formatters/table.rb +26 -0
  46. data/lib/greenhat/thing/formatters/time_json.rb +21 -0
  47. data/lib/greenhat/thing/formatters/time_shellwords.rb +28 -0
  48. data/lib/greenhat/thing/formatters/time_space.rb +36 -0
  49. data/lib/greenhat/thing/helpers.rb +71 -0
  50. data/lib/greenhat/thing/history.rb +51 -0
  51. data/lib/greenhat/thing/info_format.rb +193 -0
  52. data/lib/greenhat/thing/kind.rb +97 -0
  53. data/lib/greenhat/thing/spinner.rb +52 -0
  54. data/lib/greenhat/thing/super_log.rb +102 -0
  55. data/lib/greenhat/tty/custom_line.rb +29 -0
  56. data/lib/greenhat/tty/line.rb +326 -0
  57. data/lib/greenhat/tty/reader.rb +110 -0
  58. data/lib/greenhat/version.rb +3 -0
  59. data/lib/greenhat/views/css.slim +126 -0
  60. data/lib/greenhat/views/disk_free.slim +18 -0
  61. data/lib/greenhat/views/index.slim +51 -0
  62. data/lib/greenhat/views/info.slim +39 -0
  63. data/lib/greenhat/views/manifest.slim +22 -0
  64. data/lib/greenhat/views/memory.slim +18 -0
  65. data/lib/greenhat/views/netstat.slim +20 -0
  66. data/lib/greenhat/views/process.slim +21 -0
  67. data/lib/greenhat/views/systemctl.slim +40 -0
  68. data/lib/greenhat/views/ulimit.slim +15 -0
  69. data/lib/greenhat/web.rb +46 -0
  70. metadata +476 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fbb51c051ab366c7bb7a172c4a917d7646bd5bdbc00c894217403655130bb2f3
4
+ data.tar.gz: b4e997388954091b257df23a1f67093490b8c1996635c860b3e462fa3f44213c
5
+ SHA512:
6
+ metadata.gz: 965baad78deb383ed1c1cb569a219439daa4c73adf7fd8b3f2852ee1b9703e758e91b0784ac1c1ac999045dd8a0d871927680d2718829ebcc3740dcc4c334a00
7
+ data.tar.gz: 17111df14082319b62bca88224ccf4b0b433ac9bcda5d1fe9c922e08477632a6c0831f61dc8615f633f0d8c4b70c58d54fe765c63172c4f4573b6812fc61aee1
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # GreenHat
2
+
3
+ Experimental SOS and Log Parser for GitLab
4
+
5
+ 12.x and above only (due to structured logging)
6
+
7
+ # Requirements
8
+
9
+ `bsdtar` - Used to extract archives
10
+
11
+ ### Ubuntu
12
+
13
+ `apt-get install libarchive-tools`
14
+
15
+ ## Installation
16
+
17
+ While potentially so in the future, this is currently not a published gem. To install:
18
+
19
+ ```
20
+ git clone https://gitlab.com/gitlab-com/support/toolbox/greenhat
21
+ cd greenhat
22
+ bundle install
23
+ bundle exec rake install
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```
29
+ greenhat sos-archive.tar.gz
30
+ greenhat production_log.json
31
+ # launches a console
32
+ >> help # the program is self-documented through the builtin help command
33
+ ```
34
+
35
+ ## Testing
36
+
37
+ ```
38
+ bundle exec rake
39
+ ```
40
+
41
+ ## Release Process
42
+
43
+ - Update CHANGELOG
44
+ - Increment `version.rb`
45
+ - Create MR
46
+ - Merge to Master
47
+
48
+ ```
49
+ # Build and Push
50
+ bundle exec rake build
51
+ gem push pkg/greenhat-1.x.x.gem
52
+ ```
53
+
54
+ ## Contributing
55
+
56
+ Bug reports and merge requests are welcome on GitLab at https://gitlab.com/gitlab-com/support/toolbox/greenhat. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
57
+
58
+ ## Limitations
59
+
60
+ - Shell Helpers cannot use Camel Case
61
+
62
+ ## License
63
+
64
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/greenhat ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'greenhat'
4
+
5
+ # DEV ONLY
6
+ require 'pry'
7
+
8
+ Dir.mktmpdir('greenhat-sauce') do |tmp|
9
+ $TMP = tmp
10
+ $STDOUT_CLONE = $stdout.clone
11
+ GreenHat::Cli.start ARGV
12
+ end
data/lib/greenhat.rb ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'action_view'
4
+ require 'benchmark'
5
+ require 'find'
6
+ require 'tty-prompt'
7
+ require 'tty-spinner'
8
+ require 'tty-table'
9
+ require 'tty-pager'
10
+ require 'tty-cursor'
11
+ require 'tty-reader'
12
+ require 'hash_dot'
13
+ require 'oj'
14
+ require 'slim'
15
+ require 'active_support'
16
+ require 'active_support/core_ext'
17
+ require 'pry'
18
+ require 'amazing_print'
19
+ require 'colorize'
20
+ require 'semantic'
21
+ require 'tty-progressbar'
22
+ require 'require_all'
23
+ require 'warning'
24
+ require 'dotenv'
25
+
26
+ # Custom Gem
27
+ require 'teron'
28
+
29
+ # Oj Settings
30
+ Oj.default_options = { symbol_keys: true, mode: :compat }
31
+
32
+ # Amazing Print
33
+ AmazingPrint.defaults = {
34
+ indent: -2,
35
+ ruby19_syntax: true,
36
+ index: false,
37
+ sort_keys: true,
38
+ sort_vars: true
39
+ }
40
+
41
+ # HashDot Instead of Struct
42
+ Hash.use_dot_syntax = true
43
+ Hash.hash_dot_use_default = true
44
+
45
+ # Load Required Files
46
+ require 'greenhat/version'
47
+ require 'greenhat/cli'
48
+ require 'greenhat/archive'
49
+ require 'greenhat/host'
50
+ require 'greenhat/logbot'
51
+ require 'greenhat/settings'
52
+
53
+ # Formatters - Loads Required Files Automatically
54
+ require 'greenhat/thing/super_log'
55
+ require 'greenhat/thing/file_types'
56
+ require 'greenhat/thing/kind'
57
+ require 'greenhat/thing/history'
58
+
59
+ # Thing
60
+ require 'greenhat/thing/helpers'
61
+ require 'greenhat/thing/spinner'
62
+ require 'greenhat/thing'
63
+
64
+ # Shell - Loads Required Files Automatically
65
+ require 'greenhat/shell'
66
+
67
+ # TODO: Confirm
68
+ # require 'greenhat/thing/log_format'
69
+ # require 'greenhat/host'
70
+ # require 'greenhat/web'
71
+
72
+ require 'greenhat/pry_helpers'
73
+
74
+ ## TTY Shims
75
+
76
+ require 'greenhat/tty/line'
77
+ require 'greenhat/tty/reader'
78
+ require 'greenhat/tty/custom_line'
79
+
80
+ Warning.ignore(/The table size exceeds the currently set width/)
@@ -0,0 +1,27 @@
1
+ module GreenHat
2
+ # Sidekiq Log Helpers
3
+ module Disk
4
+ def self.data
5
+ df.map(&:data).flatten.compact
6
+ end
7
+
8
+ # Get Max Size
9
+ def self.max_padding(disks, key = :mounted_on)
10
+ list = disks.map do |x|
11
+ x.slice(key)
12
+ end
13
+
14
+ list.map(&:values).flatten.max_by(&:size).size + 4
15
+ end
16
+
17
+ def self.padding(disks, keys = %i[mounted_on size used avail])
18
+ keys.map do |key|
19
+ max_padding(disks, key)
20
+ end
21
+ end
22
+
23
+ def self.df
24
+ Thing.where(name: 'df_h')
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ module GreenHat
2
+ # Sidekiq Log Helpers
3
+ module Production
4
+ def self.fast_stats
5
+ things.each do |thing|
6
+ puts `fast-stats #{thing.file}`
7
+ end
8
+
9
+ :ok!
10
+ end
11
+
12
+ def self.logs
13
+ @logs ||= things.map(&:data).flatten.compact
14
+ end
15
+
16
+ def self.raw
17
+ @raw ||= things.map(&:raw).flatten.compact
18
+ end
19
+
20
+ def self.things
21
+ Thing.where(name: 'gitlab_rails_production_json_log')
22
+ end
23
+
24
+ def self.errors
25
+ logs.select { |x| x.severity == 'ERROR' }
26
+ end
27
+
28
+ def self.pages
29
+ show logs
30
+ end
31
+
32
+ def self.queue_duration(data = nil)
33
+ data ||= logs
34
+ data.select { |x| x.key? :enqueued_at }.each do |row|
35
+ next if row.key? :queue_duration
36
+
37
+ row[:queue_duration] = row.enqueued_at - row.created_at
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module GreenHat
2
+ # Sidekiq Log Helpers
3
+ module Sidekiq
4
+ def self.fast_stats
5
+ things.each do |thing|
6
+ puts `fast-stats #{thing.file}`
7
+ end
8
+
9
+ :ok!
10
+ end
11
+
12
+ def self.logs
13
+ @logs ||= things.map(&:data).flatten.compact
14
+ end
15
+
16
+ def self.raw
17
+ @raw ||= things.map(&:raw).flatten.compact
18
+ end
19
+
20
+ def self.things
21
+ Thing.where(name: 'sidekiq_current')
22
+ end
23
+
24
+ def self.errors
25
+ logs.select { |x| x.severity == 'ERROR' }
26
+ end
27
+
28
+ def self.pages
29
+ show logs
30
+ end
31
+
32
+ def self.queue_duration(data = nil)
33
+ data ||= logs
34
+ data.select { |x| x.key? :enqueued_at }.each do |row|
35
+ next if row.key? :queue_duration
36
+
37
+ row[:queue_duration] = row.enqueued_at - row.created_at
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module GreenHat
2
+ # Sidekiq Log Helpers
3
+ module Memory
4
+ def self.free
5
+ Thing.where(name: 'free_m')
6
+ end
7
+
8
+ def self.percentage(used, total)
9
+ return 0 if used.to_i.zero?
10
+
11
+ # Show at least one bar if below 1%
12
+ [1, ((used.to_i / total.to_f).round(1) * 100).round].max
13
+ end
14
+
15
+ def self.memory_row(mem)
16
+ total = mem.total.to_i
17
+ total_name = number_to_human_size(total.megabytes)
18
+ used_name = number_to_human_size(mem.used.to_i.megabytes)
19
+
20
+ bar = [
21
+ '|'.colorize(:green) * percentage(mem.used, total),
22
+ '|'.colorize(:blue) * percentage(mem.shared, total),
23
+ '|'.colorize(:teal) * percentage(mem.buffcache, total),
24
+ ' ' * percentage(mem.free, total)
25
+ ].join
26
+
27
+ # Make Even
28
+ padding = 125 - bar.uncolorize.size
29
+ bar += ' ' * padding if padding.positive?
30
+
31
+ [
32
+ mem.kind.ljust(4).colorize(:cyan),
33
+ ' ['.colorize(:light_black),
34
+ bar.ljust(120),
35
+ used_name.colorize(:magenta),
36
+ ' / '.colorize(:light_black),
37
+ total_name.colorize(:blue),
38
+ ']'.colorize(:light_black)
39
+ ].join
40
+ end
41
+
42
+ def self.number_to_human_size(num)
43
+ ActiveSupport::NumberHelper.number_to_human_size num
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,8 @@
1
+ module GreenHat
2
+ # Sidekiq Log Helpers
3
+ module Network
4
+ def self.netstat
5
+ Thing.where(name: 'netstat')
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module GreenHat
2
+ # Sidekiq Log Helpers
3
+ module Ps
4
+ def self.ps
5
+ Thing.where(name: 'ps')
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,108 @@
1
+ # Top level namespace
2
+ module GreenHat
3
+ # Archive Manipulator
4
+ module ArchiveLoader
5
+ def self.load(archive_path)
6
+ path = "#{$TMP}/#{SecureRandom.uuid}"
7
+ Dir.mkdir path
8
+
9
+ # Initially Copy file into tmpdir
10
+ FileUtils.cp(archive_path, "#{path}/")
11
+
12
+ # Extract Everything
13
+ loop do
14
+ archive_list = Find.find(path).reject { |x| File.directory? x }.select { |y| archive? y }
15
+ break if archive_list.empty?
16
+
17
+ archive_list.each do |archive|
18
+ # Different File Type Handler
19
+ unpack(archive, path)
20
+ end
21
+ end
22
+
23
+ # Ignore Directories
24
+ list = Find.find(path).reject { |x| File.directory? x }
25
+
26
+ # Ignore Empty Files
27
+ list.reject! { |x| File.size(x).zero? }
28
+
29
+ archive = Archive.new(name: archive_path, path: path)
30
+ archive.save
31
+ # file = list[2]
32
+ # thing = archive.things_create(file: file)
33
+ # thing.setup
34
+
35
+ list.each do |file|
36
+ # Ensure Valid Content
37
+ next if missing_command(file)
38
+
39
+ # Thread.new do
40
+ thing = archive.things_create(file: file)
41
+ thing.setup
42
+ # end
43
+ end
44
+ end
45
+
46
+ # Ignore No Commands
47
+ # rubocop:disable Style/SymbolProc
48
+ def self.missing_command(file)
49
+ first_line = File.open(file) { |f| f.readline }
50
+ ['command not found', ': not found'].any? { |x| first_line.include? x }
51
+ end
52
+ # rubocop:enable Style/SymbolProc
53
+
54
+ # Handle Different Types of Archives
55
+ def self.unpack(archive_path, path)
56
+ case File.extname archive_path
57
+ when '.tar'
58
+ `bsdtar -xf "#{archive_path}" -C #{path}`
59
+ FileUtils.rm(archive_path)
60
+ when '.gz'
61
+ `gzip -d "#{archive_path}"`
62
+ when '.s'
63
+ # Find Original Directory, Split Path, Rename to .gz
64
+ base_path = archive_path.gsub(File.basename(archive_path), '')
65
+ FileUtils.mv(archive_path, "#{base_path}/#{File.basename(archive_path, '.s')}.gz")
66
+ else
67
+ FileUtils.cp(archive_path, "#{path}/#{archive_path}")
68
+ end
69
+ end
70
+
71
+ def self.archive?(file_name)
72
+ archive_types.any? do |type|
73
+ file_name.match?(/(\.#{type})$/)
74
+ end
75
+ end
76
+
77
+ def self.archive_types
78
+ %w[s gz tar]
79
+ end
80
+ # -- Archive Loader ----------------------------------------------
81
+ end
82
+ # Archive End
83
+ end
84
+
85
+ # Archive Parent
86
+ class Archive < Teron
87
+ has_one :host
88
+ has_many :things
89
+
90
+ field :path
91
+ field :name
92
+
93
+ # TODO: Fix from Number of Files / Needed?
94
+ def friendly_name
95
+ # Difficult with multiple Archives
96
+ # File.basename(name, '.tar.gz').gsub('gitlabsos.', '').split('_', 2).first
97
+
98
+ File.basename(name, File.extname(name)).gsub('gitlabsos.', '')
99
+ end
100
+
101
+ def inspect
102
+ "#<Archive name: '#{name}'>"
103
+ end
104
+
105
+ def report
106
+ GreenHat::Report.new(self)
107
+ end
108
+ end