greenhat 0.3.2 → 0.3.6

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/greenhat/accessors/disk.rb +42 -3
  3. data/lib/greenhat/accessors/gitlab.rb +30 -1
  4. data/lib/greenhat/accessors/memory.rb +1 -1
  5. data/lib/greenhat/archive.rb +11 -2
  6. data/lib/greenhat/cli.rb +37 -0
  7. data/lib/greenhat/host.rb +25 -37
  8. data/lib/greenhat/shell/args.rb +22 -9
  9. data/lib/greenhat/shell/faststats.rb +23 -3
  10. data/lib/greenhat/shell/field_helper.rb +1 -1
  11. data/lib/greenhat/shell/filter_help.rb +232 -9
  12. data/lib/greenhat/shell/log.rb +153 -9
  13. data/lib/greenhat/shell/markdown.rb +352 -0
  14. data/lib/greenhat/shell/old_search_helper.rb +54 -0
  15. data/lib/greenhat/shell/page.rb +1 -1
  16. data/lib/greenhat/shell/pipe.rb +31 -0
  17. data/lib/greenhat/shell/platform.rb +28 -0
  18. data/lib/greenhat/shell/report.rb +106 -25
  19. data/lib/greenhat/shell/shell_helper.rb +114 -106
  20. data/lib/greenhat/shell.rb +7 -0
  21. data/lib/greenhat/thing/file_types.rb +126 -7
  22. data/lib/greenhat/thing/formatters/json.rb +4 -0
  23. data/lib/greenhat/thing/formatters/kube_json.rb +36 -0
  24. data/lib/greenhat/thing/formatters/kube_nginx.rb +48 -0
  25. data/lib/greenhat/thing/formatters/kube_webservice.rb +51 -0
  26. data/lib/greenhat/thing/formatters/nginx.rb +6 -2
  27. data/lib/greenhat/thing/formatters/registry.rb +47 -0
  28. data/lib/greenhat/thing/formatters/time_space.rb +0 -16
  29. data/lib/greenhat/thing/helpers.rb +12 -0
  30. data/lib/greenhat/thing.rb +10 -0
  31. data/lib/greenhat/version.rb +1 -1
  32. data/lib/greenhat/views/api.slim +55 -0
  33. data/lib/greenhat/views/chart.slim +42 -0
  34. data/lib/greenhat/views/chart_template.slim +31 -0
  35. data/lib/greenhat/views/chartkick.js +21 -0
  36. data/lib/greenhat/views/css.slim +47 -0
  37. data/lib/greenhat/views/gitaly.slim +53 -0
  38. data/lib/greenhat/views/headers.slim +16 -0
  39. data/lib/greenhat/views/index-old.slim +51 -0
  40. data/lib/greenhat/views/index.slim +14 -14
  41. data/lib/greenhat/views/info.slim +17 -18
  42. data/lib/greenhat/views/production.slim +55 -0
  43. data/lib/greenhat/views/sidekiq.slim +55 -0
  44. data/lib/greenhat/views/time.slim +63 -0
  45. data/lib/greenhat/views/workhorse.slim +16 -0
  46. data/lib/greenhat/web/api.rb +94 -0
  47. data/lib/greenhat/web/chartkick_shim.rb +14 -0
  48. data/lib/greenhat/web/faststats.rb +44 -0
  49. data/lib/greenhat/web/gitaly.rb +65 -0
  50. data/lib/greenhat/web/helpers.rb +198 -0
  51. data/lib/greenhat/web/production.rb +104 -0
  52. data/lib/greenhat/web/sidekiq.rb +73 -0
  53. data/lib/greenhat/web/stats_helpers.rb +74 -0
  54. data/lib/greenhat/web/time.rb +36 -0
  55. data/lib/greenhat/web/workhorse.rb +43 -0
  56. data/lib/greenhat/web.rb +63 -19
  57. data/lib/greenhat.rb +1 -0
  58. metadata +73 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db336e98cd2a446c371d866d068eb9b485f9782b2ea7182f4b4da651011e2083
4
- data.tar.gz: 90b1858171c14ebe93e3a0ff42dffe2965602835f8f2cc98178f6a81ec816352
3
+ metadata.gz: d9cc86956963d9d4d6a11b8d84b3a047d66bbbd3ac1c0cbb45f7e9f91d0a55e2
4
+ data.tar.gz: c4df69de408709de93713f4e2a98ce6263f15b83c28bc3c353589368bb325efd
5
5
  SHA512:
6
- metadata.gz: 94d78c52d3e4b800ac90798d8030dfa9962c7e7c628bd8b636f5471fcf2c35044aa044a91edbd412827db2daf36117ab47cfecc4c6a85e49875e3e6d7756e1d0
7
- data.tar.gz: fad9f87be4735b5d028ccc7e251fce423de9cf0d440253b65dbaddbc36b268234ffedc7277f9207131692bcf8ea74cd9a4b70c433f55e158b6cd30aae73edf1d
6
+ metadata.gz: 813350d41deb97b978afc55d3aad33e3bf1b383a721ab3a33b8ed56cfdd4b2158ba5c6e7368839d3f7ac74e53614c644e2f92a3a6ccc64608d1b89c5274396a1
7
+ data.tar.gz: 78074ff71327905079cbd603d640d09625d4e49bf1dc9e8a7e7823b8ba923d1abb0c69c833a0a956aa6d0e1af92e53bbae97015827d83219d8c384abf8a349b0
@@ -30,7 +30,6 @@ module GreenHat
30
30
  end
31
31
 
32
32
  # Unified Output Handler
33
- # rubocop:disable Metrics/MethodLength
34
33
  def self.format_output(file, name = false, limit = nil, filter = %w[tmpfs loop])
35
34
  output = []
36
35
 
@@ -62,7 +61,7 @@ module GreenHat
62
61
  disk.use.rjust(5).ljust(5).pastel(:green),
63
62
  ' ['.pastel(:blue),
64
63
  ('=' * (disk.use.to_i / 2)).pastel(:green),
65
- ' ' * (50 - disk.use.to_i / 2),
64
+ ' ' * (50 - (disk.use.to_i / 2)),
66
65
  ']'.pastel(:blue)
67
66
  ].join
68
67
 
@@ -78,6 +77,46 @@ module GreenHat
78
77
 
79
78
  output
80
79
  end
81
- # rubocop:enable Metrics/MethodLength
80
+
81
+ # Unified Output Handler
82
+ def self.markdown_format(file, name = false, limit = nil, filter = %w[tmpfs loop])
83
+ output = []
84
+
85
+ output << file.friendly_name if name
86
+
87
+ # Reject TMPFS
88
+ disks = file.data.sort_by { |x| x.use.to_i }.reverse
89
+
90
+ # Filter
91
+ disks.reject! { |x| filter.any? { |y| x.filesystem.include? y } }
92
+
93
+ disks = disks[0..limit - 1] if limit
94
+
95
+ pad_mount, pad_size, pad_used, pad_avail = GreenHat::Disk.padding(disks)
96
+
97
+ # Headers
98
+ output << [
99
+ 'Mount'.ljust(pad_mount),
100
+ 'Size'.ljust(pad_size),
101
+ 'Used'.ljust(pad_used),
102
+ 'Avail'.ljust(pad_avail),
103
+ '% Use'.ljust(pad_avail)
104
+ ].join
105
+
106
+ # Table Summary
107
+ disks.map do |disk|
108
+ # Whole Thing
109
+ output << [
110
+ disk.mounted_on.ljust(pad_mount),
111
+ disk[:size].to_s.ljust(pad_size),
112
+ disk.used.to_s.ljust(pad_used),
113
+ disk.avail.to_s.ljust(pad_avail),
114
+ disk.use.rjust(5).ljust(5)
115
+ ].join
116
+ end
117
+
118
+ output
119
+ end
120
+ # =
82
121
  end
83
122
  end
@@ -35,6 +35,7 @@ module GreenHat
35
35
  end
36
36
 
37
37
  # Show GitLab Services in a grid / include versions
38
+ # rubocop:disable Metrics/PerceivedComplexity
38
39
  def self.services(archive, indent = 0)
39
40
  manifest = archive.things.find { |x| x.type == 'gitlab/version-manifest.json' }
40
41
  gitlab_status = archive.things.find { |x| x.name == 'gitlab_status' }
@@ -43,6 +44,7 @@ module GreenHat
43
44
 
44
45
  list = gitlab_status.data.keys.sort.map do |service|
45
46
  color = gitlab_status.data.dig(service, 0, :status) == 'run' ? :green : :red
47
+ status = gitlab_status.data.dig(service, 0, :status) == 'run' ? '↑' : '↓'
46
48
 
47
49
  # Collect Service version from manifest
48
50
  version = manifest.data.software[service.to_sym]&.display_version
@@ -50,7 +52,7 @@ module GreenHat
50
52
  # If able to identify version use / fallback
51
53
  if version
52
54
  [
53
- service.pastel(color),
55
+ "#{service}#{status}".pastel(color),
54
56
  "(#{version})".pastel(:bright_black)
55
57
  ].join(' ')
56
58
  else
@@ -71,5 +73,32 @@ module GreenHat
71
73
 
72
74
  table.render(:unicode, padding: [0, 1, 0, 1], indent: indent)
73
75
  end
76
+ # rubocop:enable Metrics/PerceivedComplexity
77
+
78
+ def self.services_markdown(archive)
79
+ # manifest = archive.things.find { |x| x.type == 'gitlab/version-manifest.json' }
80
+ gitlab_status = archive.things.find { |x| x.name == 'gitlab_status' }
81
+
82
+ list = gitlab_status.data.keys.sort.map do |service|
83
+ status = gitlab_status.data.dig(service, 0, :status) == 'run' ? '↑' : '↓'
84
+
85
+ "#{service}#{status}"
86
+ end
87
+
88
+ # Keep Alphabetical Sort
89
+ groups = list.each_slice((list.size / 3.to_f).round).to_a
90
+
91
+ table = TTY::Table.new do |t|
92
+ loop do
93
+ break if groups.all?(&:empty?)
94
+
95
+ t << groups.map(&:shift)
96
+ end
97
+ end
98
+
99
+ "```\n#{table.render(:basic)}\n```"
100
+ end
101
+
102
+ # ==
74
103
  end
75
104
  end
@@ -6,7 +6,7 @@ module GreenHat
6
6
  end
7
7
 
8
8
  def self.percentage(used, total)
9
- return 0 if used.to_i.zero?
9
+ return 0 if used.to_i.zero? || total.to_i.zero?
10
10
 
11
11
  # Show at least one bar if below 1%
12
12
  [1, ((used.to_i / total.to_f).round(1) * 100).round].max
@@ -102,7 +102,16 @@ class Archive < Teron
102
102
  "#<Archive name: '#{name}'>"
103
103
  end
104
104
 
105
- def report
106
- GreenHat::Report.new(self)
105
+ def report(flags)
106
+ GreenHat::Report.new(self, flags)
107
+ end
108
+
109
+ def report_markdown
110
+ GreenHat::ReportMarkdown.new(self)
111
+ end
112
+
113
+ # Helper for finding thing
114
+ def thing?(thing_name = 'gitlab-workhorse/current')
115
+ things.find { |x| x.name == thing_name }
107
116
  end
108
117
  end
data/lib/greenhat/cli.rb CHANGED
@@ -348,6 +348,7 @@ module GreenHat
348
348
  @quiet = !@quiet
349
349
  end
350
350
 
351
+ # rubocop:disable Metrics/MethodLength
351
352
  def self.cli_help
352
353
  Shell.version
353
354
  puts
@@ -361,6 +362,14 @@ module GreenHat
361
362
  puts ' Run `report` against archives and exit'
362
363
  puts
363
364
 
365
+ puts ' --full-report, -f'.pastel(:green)
366
+ puts ' Run `report` with all details. e.g. include fast-stats top/errors'
367
+ puts
368
+
369
+ puts ' --markdown, -m'.pastel(:green)
370
+ puts ' Run `markdown_report` against archives and exit'
371
+ puts
372
+
364
373
  puts ' --quiet, -r'.pastel(:green)
365
374
  puts ' Surpress GreenHat logging output'
366
375
  puts
@@ -373,10 +382,19 @@ module GreenHat
373
382
  puts ' Run and then exit a GreenHat Shell command'
374
383
  puts
375
384
 
385
+ puts ' --web, -w'.pastel(:green)
386
+ puts ' Start Sinatra Webservice on load (4567)'
387
+ puts
388
+
389
+ puts ' --no-color, -n'.pastel(:green)
390
+ puts ' Disable color output'
391
+ puts
392
+
376
393
  puts ' --version, -v'.pastel(:green)
377
394
  puts ' Print version and exit'
378
395
  puts
379
396
  end
397
+ # rubocop:enable Metrics/MethodLength
380
398
 
381
399
  # Arguments before general processing
382
400
  def self.pre_args(flags, files)
@@ -408,20 +426,38 @@ module GreenHat
408
426
 
409
427
  # Arguments to be handled after general processing
410
428
  def self.post_args(flags)
429
+ # Supress Color
430
+ GreenHat::Settings.settings[:color] = false if flags?(%i[no-color n], flags)
431
+
411
432
  # Run report and exit / Don't Clear for reports
412
433
  if flags?(%i[report r], flags)
413
434
  @quiet = true
414
435
  # Don't Use Pagination
415
436
  GreenHat::Shell.report(['--raw'])
416
437
  exit 0
438
+ elsif flags?(%i[full-report f], flags)
439
+ @quiet = true
440
+ # Don't Use Pagination
441
+ GreenHat::Shell.report(['--raw', '--full'])
442
+ exit 0
443
+ elsif flags?(%i[markdown m], flags)
444
+ @quiet = true
445
+ # Don't Use Pagination
446
+ GreenHat::Shell.markdown_report(['--raw'])
447
+ exit 0
417
448
  else
418
449
  clear_screen
419
450
  end
451
+ end
420
452
 
453
+ def self.post_setup(flags)
421
454
  # CTL Tails need to be parsed for new 'things'
422
455
  Thing.where(kind: :gitlab_tail)&.map(&:process)
456
+ Thing.where(kind: :kube_webservice)&.map(&:process)
423
457
 
424
458
  Thing.all.each(&:process) if flags?(%i[load l], flags)
459
+
460
+ Shell.web if flags?(%i[web w], flags)
425
461
  end
426
462
 
427
463
  # Helper to Simplify checking flags
@@ -437,6 +473,7 @@ module GreenHat
437
473
  load_files files
438
474
  run_command(args) if args.any? { |arg| run_command?(arg) }
439
475
  post_args(flags)
476
+ post_setup(flags)
440
477
 
441
478
  value ||= '' # Empty Start
442
479
 
data/lib/greenhat/host.rb CHANGED
@@ -14,17 +14,23 @@ class Host < Teron
14
14
  # end
15
15
 
16
16
  def archive_name
17
- File.basename archive
17
+ archive.friendly_name
18
18
  end
19
19
 
20
20
  def find_file(file_name)
21
21
  files.find { |x| x.name == file_name }
22
22
  end
23
23
 
24
- def icon
25
- release_file = find_file files.map(&:name).grep(/_release/).first
24
+ def things
25
+ archive.things
26
+ end
26
27
 
27
- release = release_file.raw.join
28
+ def find_thing(param)
29
+ things.find { |x| x.name.include? param }
30
+ end
31
+
32
+ def icon
33
+ release = find_thing('etc/os-release').data['ID_LIKE']
28
34
 
29
35
  if release.include? 'ubuntu'
30
36
  'fa-ubuntu'
@@ -57,41 +63,36 @@ class Host < Teron
57
63
  end
58
64
  # ---------------------------
59
65
 
60
- def manifest
61
- file = find_file 'gitlab_version_manifest_json'
66
+ def gitlab_version
67
+ file = find_thing 'gitlab/version-manifest.json'
62
68
  return nil unless file
63
69
 
64
- Oj.load file.raw.join
70
+ file.data.build_version
65
71
  end
66
72
 
67
73
  def uptime
68
- file = find_file 'uptime'
74
+ file = find_thing 'uptime'
69
75
  return nil unless file
70
76
 
71
77
  file.raw
72
78
  end
73
79
 
74
80
  def uname
75
- file = find_file 'uname'
81
+ file = find_thing 'uname'
76
82
  return nil unless file
77
83
 
78
84
  file.raw.join
79
85
  end
80
86
 
81
87
  def cpuinfo
82
- file = find_file 'cpuinfo'
88
+ file = find_thing 'lscpu'
83
89
  return nil unless file
84
90
 
85
- file.raw.join("\n").split("\n\n").map do |cpu|
86
- all = cpu.split("\n").map do |row|
87
- row.delete("\t").split(': ')
88
- end
89
- { details: all[1..], order: all[0].last }
90
- end
91
+ file.data
91
92
  end
92
93
 
93
94
  def cpu_speed
94
- file = find_file 'lscpu'
95
+ file = find_thing 'lscpu'
95
96
  return nil unless file
96
97
 
97
98
  details = file.raw.find { |x| x.include? 'MHz' }
@@ -99,7 +100,7 @@ class Host < Teron
99
100
  end
100
101
 
101
102
  def total_memory
102
- file = find_file 'free_m'
103
+ file = find_thing 'free_m'
103
104
  return nil unless file
104
105
 
105
106
  value = file.raw.dig(1, 1).to_i
@@ -107,28 +108,28 @@ class Host < Teron
107
108
  end
108
109
 
109
110
  def free_m
110
- file = find_file 'free_m'
111
+ file = find_thing 'free_m'
111
112
  return nil unless file
112
113
 
113
114
  file.raw
114
115
  end
115
116
 
116
117
  def df_h
117
- file = find_file 'df_h'
118
+ file = find_thing 'df_h'
118
119
  return nil unless file
119
120
 
120
121
  file.raw
121
122
  end
122
123
 
123
124
  def netstat
124
- file = find_file 'netstat'
125
+ file = find_thing 'netstat'
125
126
  return nil unless file
126
127
 
127
128
  file.raw
128
129
  end
129
130
 
130
131
  def ulimit
131
- file = find_file 'ulimit'
132
+ file = find_thing 'ulimit'
132
133
  return nil unless file
133
134
 
134
135
  results = file.raw.map do |entry|
@@ -142,7 +143,7 @@ class Host < Teron
142
143
  end
143
144
 
144
145
  def processes
145
- file = find_file 'ps'
146
+ file = find_thing 'ps'
146
147
  return nil unless file
147
148
 
148
149
  headers = file.raw.first.split(' ', 11)
@@ -155,7 +156,7 @@ class Host < Teron
155
156
  end
156
157
 
157
158
  def systemctl_unit_files
158
- file = find_file 'systemctl_unit_files'
159
+ file = find_thing 'systemctl_unit_files'
159
160
  return nil unless file
160
161
 
161
162
  all = file.raw[1..-2].map do |x|
@@ -167,16 +168,3 @@ class Host < Teron
167
168
  all.sort_by(&:unit)
168
169
  end
169
170
  end
170
-
171
- # # Slim Wrapper
172
- # class List
173
- # attr_accessor :hosts
174
-
175
- # def initialize
176
- # self.hosts = []
177
- # end
178
-
179
- # def slim(file, host = nil)
180
- # Slim::Template.new("#{__dir__}/views/#{file}.slim").render(host)
181
- # end
182
- # end
@@ -1,12 +1,5 @@
1
1
  module GreenHat
2
2
  # Module for Argument Parsing
3
- # Possible Args
4
- # --value=thing
5
- # --value / Default => --value=thing
6
- # --flag
7
- # --slice=value,value2
8
- # files
9
-
10
3
  # Variable Breakdown
11
4
  # Args:Array supplied or default values for entry looping action
12
5
  # Flags:Hash Key/Value filter Actionables
@@ -15,7 +8,14 @@ module GreenHat
15
8
  def self.parse(raw, skip_flags = [])
16
9
  # Don't affect original object / Better deep clone?
17
10
  cmd = raw.clone
18
- # cmd = Marshal.load(Marshal.dump(raw))
11
+
12
+ # Handle Pipe Params
13
+ pipe = nil
14
+ if cmd.include?('|')
15
+ list = cmd.split('|')
16
+ cmd = list.shift
17
+ pipe = list.map { |x| x.join(' ') }.join('|')
18
+ end
19
19
 
20
20
  # Extract Files
21
21
  files = cmd.grep_v(/^-+([^=]+)/)
@@ -33,6 +33,9 @@ module GreenHat
33
33
  # And / Or
34
34
  flag_defaults(flags, skip_flags)
35
35
 
36
+ # Set command includes
37
+ flags[:pipe] = pipe if pipe
38
+
36
39
  [files, flags, args]
37
40
  end
38
41
 
@@ -78,19 +81,29 @@ module GreenHat
78
81
  # Arg Scan (Split -- values into keys)
79
82
  def self.arg_scan(arg)
80
83
  arg.scan(/^-+([^=]+)=(.*)/).map do |field, value|
84
+ logic = :include?
81
85
  bang = false
86
+
87
+ # Exclude Logic
82
88
  if field.include? '!'
83
89
  field.delete!('!')
84
90
  bang = true
85
91
  end
86
92
 
93
+ # Numeric Magic Logic
94
+ logic = :<= if field.include? '<'
95
+ logic = :>= if field.include? '>'
96
+ field.delete!('<')
97
+ field.delete!('>')
98
+
87
99
  # Symbolize
88
100
  field = field.to_sym
89
101
 
90
102
  {
91
103
  field: field,
92
104
  value: arg_normalize(field, value),
93
- bang: bang
105
+ bang: bang,
106
+ logic: logic
94
107
  }
95
108
  end
96
109
  end
@@ -137,7 +137,7 @@ module GreenHat
137
137
  # --limit=X
138
138
  # --sort=count,fail,max,median,min,p95,p99,rps,score
139
139
  # ========================================================================
140
- def self.top(raw)
140
+ def self.top(raw = [], internal = false)
141
141
  unless TTY::Which.exist? 'fast-stats'
142
142
  faststats_installation
143
143
  return false
@@ -155,6 +155,9 @@ module GreenHat
155
155
  ]
156
156
  end
157
157
 
158
+ # Quick exit for internal processing
159
+ return results.flatten if internal
160
+
158
161
  ShellHelper.show(results.flatten, flags)
159
162
  end
160
163
  # ========================================================================
@@ -162,14 +165,14 @@ module GreenHat
162
165
  # ========================================================================
163
166
  # ===== [ Fast Stats - Errors ] ====================
164
167
  # ========================================================================
165
- def self.errors(raw)
168
+ def self.errors(raw = [], internal = false)
166
169
  unless TTY::Which.exist? 'fast-stats'
167
170
  faststats_installation
168
171
  return false
169
172
  end
170
173
 
171
174
  # Add Color Output
172
- raw.push '--color-output'
175
+ raw.push '--color-output' if Settings.settings.color?
173
176
  files, flags, cmd = ShellHelper::Faststats.parse(raw)
174
177
 
175
178
  LogBot.debug('FastStats CMD', cmd) if ENV['DEBUG']
@@ -182,6 +185,9 @@ module GreenHat
182
185
  ]
183
186
  end
184
187
 
188
+ # Quick exit for internal processing
189
+ return results.flatten if internal
190
+
185
191
  ShellHelper.show(results.flatten, flags)
186
192
  end
187
193
  # ========================================================================
@@ -236,6 +242,20 @@ module GreenHat
236
242
  files.any? { |x| thing.name.include? x }
237
243
  end
238
244
  end
245
+
246
+ # =====================================
247
+ # Internal Helpers
248
+ # =====================================
249
+ def self.faststats?
250
+ TTY::Which.exist?('fast-stats')
251
+ end
252
+
253
+ def self.run(thing, cmd = '')
254
+ # Blank return if cannot possibly run
255
+ return {} unless thing || !faststats?
256
+
257
+ Oj.load `fast-stats #{cmd} #{thing.file} --format=json`
258
+ end
239
259
  end
240
260
  end
241
261
  end
@@ -60,7 +60,7 @@ module GreenHat
60
60
  auto = fields.split(',').last
61
61
 
62
62
  # Field Finder
63
- matches = fields_find(files, auto, flags)
63
+ matches = fields_find(files, auto, flags).uniq
64
64
 
65
65
  if matches.count == 1
66
66
  "--#{cmd}=#{(complete + matches).join(',')}"