tweek 0.0.1 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c0c0a75d22fc70c3d22e74318e3d957a286d597f
4
- data.tar.gz: 5928676675e148473ec09ca0358fd73e6a67d494
3
+ metadata.gz: bc8acd5816827fe451b4f223f31c70be9862dc25
4
+ data.tar.gz: 114a4da6ae11f12d5fa23edf7b43419fc0d1a78a
5
5
  SHA512:
6
- metadata.gz: f1bb49f5fff276b2cbc85ab7b31210e95e1af0e8d77f3762cae9f7cfca08010d06a31fdc3a006ad405aea0ad22a5334a9da699ecf52bd0ef15daa5e17983178c
7
- data.tar.gz: 922d61a6cd6c6891f5a6ce8b623a73bd9733c6956c905ba4f332f59d4f3ca248dadc6da2d9b551822212928efbf621d8ac24cfb48c434a00dda4b242dde3797b
6
+ metadata.gz: 6c69ab3d791fad607f25d4c6361387d3d59ac99467b9d79b2f6a94cf02c29541912c2f8af85fa430ad464b94cdf50a52e84d15f6012d35e91a2ea1753422f58d
7
+ data.tar.gz: 3b20cc0973d271c4d4a5c06aa4c6d247817cc9cd71d08a22fb8604e97d70dee21508d65b8467f8984c18ca3d643130cc126810fbfdd0215568f726e485845e10
data/bin/tweek ADDED
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # A script to check a variety of Linux system settings
4
+ # See the sample config after __END__ for a description of these.
5
+ # By Nick Townsend, June 2017
6
+ #
7
+ require 'rubygems'
8
+
9
+ require 'optparse'
10
+ require 'ostruct'
11
+ require 'tweek'
12
+ require 'tweek/app'
13
+ require 'tweek/version'
14
+
15
+ trap('INT') do
16
+ print "\n"
17
+ exit(1)
18
+ end
19
+
20
+ gflag = false
21
+ distro = nil
22
+ distro_ver = nil
23
+ kernel_ver = nil
24
+ OptionParser.new do |o|
25
+ o.banner = "Usage: #{$0} [options] [settings_file...]"
26
+ o.separator ""
27
+ o.separator "Check the system parameters specified in the settings files"
28
+ o.separator "(If not supplied then built-in defaults are used)"
29
+ o.separator "Options:"
30
+ o.on('--distro=NAME', "Set Distro (default uses lsb_release)" ) do |d|
31
+ distro = d
32
+ end
33
+ o.on('--distro-ver=X.Y.Z', "Set Distro version (default uses lsb_release)" ) do |dv|
34
+ distro_ver = dv
35
+ end
36
+ o.on('--kernel-ver=X.Y.Z', "Set Kernel version (default uses uname)" ) do |k|
37
+ kernel_ver = k
38
+ end
39
+ o.on( '-g', '--generate', "Generate a copy of the input file(s)", "containing current values on STDOUT" ) do
40
+ gflag = true
41
+ end
42
+ o.on( '-s', '--show', "Write the default parameters to STDOUT",
43
+ "Use as a fully documented starting point"
44
+ ) do
45
+ DATA.each_line{|l| STDOUT.puts l} # no copy_stream in 1.8.7
46
+ exit
47
+ end
48
+ o.on('-v', "--version", "Show version") do
49
+ puts Tweek::VERSION
50
+ exit
51
+ end
52
+ o.on( '-?', '--help', 'Display this screen' ) do
53
+ puts o
54
+ exit
55
+ end
56
+ o.separator <<MSG
57
+
58
+ Returns:
59
+ 0: If no mismatches, >0 number of mismatches
60
+ MSG
61
+ o.parse! rescue (puts "Error: #{$!}"; puts o; exit)
62
+ end
63
+ if distro.nil? or distro_ver.nil?
64
+ if RUBY_PLATFORM !~ /-linux-gnu$/
65
+ STDERR.puts "Tweek only runs on Linux!"
66
+ exit 2
67
+ end
68
+ begin
69
+ distro ||= `lsb_release -i`.partition(':').last.strip
70
+ distro_ver ||= `lsb_release -r`.partition(':').last.strip
71
+ rescue
72
+ puts "'lsb_release' not found! Install or specify --distro and --distro-ver on command line"
73
+ exit 2
74
+ end
75
+ end
76
+ if kernel_ver.nil?
77
+ begin
78
+ kernel_ver ||= `uname -r`.partition('-').first
79
+ rescue
80
+ puts "'uname' not found! Install or specify --kernel-ver on command line"
81
+ exit 2
82
+ end
83
+ end
84
+ cs = Tweek::App.new(gflag, true, distro, distro_ver, kernel_ver)
85
+ if ARGV.empty?
86
+ fh = DATA
87
+ fh.lineno -= 1
88
+ else
89
+ fh = ARGF
90
+ end
91
+ cs.read_sections(fh)
92
+ exit cs.results
93
+
94
+ __END__
95
+ # A documentation-rich sample for the parameter checking script
96
+ #
97
+ # Comments begin with # and extend to the end of the line
98
+ # Block comments are Ruby style =begin and =end
99
+ # Conditionals use 'k' for kernel version, 'v' for distro version and 'd' for distro
100
+ # Version conditionals use the http://guides.rubygems.org/patterns/#semantic-versioning
101
+ # Distro conditionals follow Ruby syntax and you may use string or regex comparisons
102
+ #
103
+ BLKDEV xvda # list one or more block devices here (filename globs OK)
104
+ read_ahead_kb = 1024 # to drive more merged IO
105
+ scheduler = noop # less CPU wasted stacking an elevator (for SSDs - still for EBS?)
106
+ rq_affinity = 2 # 1 to the CPU group, 2 to the actual CPU
107
+ nr_requests = 256
108
+
109
+ CLOCKSOURCE # Use cat /sys/devices/system/cl*/cl*/available_clocksource to see what's available
110
+ # xen is the default as supported on all instance types
111
+ # tsc is hardware supported and is significantly quicker, should be used on all post Sandybridge CPUs
112
+ clocksource0 = tsc
113
+
114
+ KERNEL # Kernel command line parameters
115
+ # true must be present, false must be absent, anything else is a value to be matched
116
+ xen_nopvspin = true
117
+ maxcpus = 63 # Set the number of physical cores, eliminates the 'B' hyperthreads
118
+ # This stops cores idling, eliminating turbo, but decrease latency of core spin-up
119
+ # intel_idle.max_cstate=1
120
+ numa = off if k>3.9 # won't move memory around between NUMA zones, useful with large working set
121
+
122
+ SYSCTL
123
+ vm.min_free_kbytes = 838608
124
+ vm.zone_reclaim = 1 if k~>4.9.0,d=='Ubuntu'
125
+ vm.zone_reclaim_mode = 1 if k~>3.13.0, k<4.9.0
126
+
127
+ # These parameters taken from Brendan Gregg's Re:Invent talk 2014
128
+ net.core.somaxconn = 1000
129
+ net.core.netdev_max_backlog = 5000
130
+ net.core.rmem_max = 16777216
131
+ net.core.wmem_max = 16777216
132
+ net.ipv4.tcp_wmem = 4096 12582912 16777216
133
+ net.ipv4.tcp_rmem = 4096 12582912 16777216
134
+ net.ipv4.tcp_max_syn_backlog = 8096
135
+
136
+ net.ipv4.tcp_slow_start_after_idle = 0
137
+
138
+ # When making lots of connections to a server enables reuse of a conn in time-wait status,
139
+ # if you run out of slots because of this then packets can get dropped!
140
+ #
141
+ net.ipv4.tcp_tw_reuse = 1
142
+ net.ipv4.ip_local_port_range = 1024 65535
143
+ net.ipv4.tcp_abort_on_overflow = 1 # allows a connection that is queued to be reset, not just dropped.
144
+ net.ipv4.tcp_fin_timeout = 50 if d=~/Amazon|RedHat/i
145
+
146
+ # Smoother page cache flushing: background flush earlier, aggressive later
147
+ # Brendan Gregg, Re:Invent 2014
148
+ #
149
+ vm.dirty_ratio = 80
150
+ vm.dirty_background_ratio = 5
151
+ vm.dirty_expire_centisecs = 12000
152
+
153
+ =begin
154
+ # These are all the recommended RedHat TCP settings
155
+ # not yet validated, so used as demo of multiline comments
156
+ net.ipv4.tcp_syn_retries = 0
157
+ net.ipv4.tcp_synack_retries = 0
158
+ net.ipv4.tcp_timestamps = 0
159
+ =end
160
+
161
+ NET eth0 # Define one or more network devices
162
+ # Check the IRQ strategy:
163
+ # aws: Use first numa node, split RSS from RPS
164
+ # RSS allocated across 0-7 (node 0), RPS on first numa node
165
+ # pin: Differs depending on number of cores
166
+ # 32 Apportion across the single node as follows:
167
+ # RPS allocated across cores 10-15 and 18-31
168
+ # RSS allocated across 0-7
169
+ # 64 Use both NUMA nodes, leave first core free on each node
170
+ # RPS allocated across remaining cores on each node
171
+ # RSS allocated across 1-4 (node 0) then 17-20 (node 1)
172
+ # null: Ignore this adapter
173
+ irqs = pin
174
+ driver = ena
175
+ # Check values in /sys/class/net/<device>/ tree
176
+ mtu = 9001
177
+ device/driver/module/version = 1.1.3
178
+
179
+ EXT4 /dev/xvda1 # Define one or more EXT4 devices or mountpoints (filename globs OK)
180
+ # Available parameters are those exposed in /proc/fs/ext4/<device>/options
181
+
182
+ barrier=true
183
+ stripe=0
184
+
185
+ XFS /mnt/xfstest # Define one or more XFS devices or mountpoints (filename globs OK)
186
+ # XFS parameters in the form "x.y" where x is log|data|naming|realtime
187
+ # and y is a valid name, eg. data.sunit or log.sunit
188
+
189
+ data.swidth = 2048
190
+ data.sunit = 128
191
+ data.bsize = 4096
192
+ log.sunit = 1
193
+
194
+ # vim: ft=ruby ts=8 sw=2 sts=2 et
data/lib/tweek/app.rb ADDED
@@ -0,0 +1,146 @@
1
+ require 'rubygems'
2
+ require 'optparse'
3
+ require 'ostruct'
4
+ require 'tweek'
5
+ require 'tweek/section'
6
+
7
+ class Tweek::App
8
+
9
+ attr_reader :distro, :distro_version, :kernel_version
10
+
11
+ def initialize( gflag, tty, distro, distro_version, kernel_version)
12
+ @distro = distro
13
+ @distro_version = Gem::Version.new(distro_version)
14
+ @kernel_version = Gem::Version.new(kernel_version)
15
+ @nparams = 0
16
+ @mismatches = []
17
+ @errors = []
18
+ @skips = []
19
+ @warns = []
20
+ @generated = []
21
+ @gflag = gflag
22
+ @tty = tty
23
+ end
24
+
25
+ # Define data-collection methods so we can easily stub them for tests
26
+ #
27
+ def self.bootline
28
+ @bootline ||= File.open("/proc/cmdline", &:read).chomp rescue 'nowt'
29
+ end
30
+
31
+ def generate type, e
32
+ return unless @gflag
33
+ case type
34
+ when :line
35
+ @generated.push "#{e.line}#{e.comment}"
36
+ when :section
37
+ @generated.push "#{e.type} #{e.list} #{e.comment}"
38
+ when :entry
39
+ cond = e.cond.nil? ? "": " if #{e.cond}"
40
+ comment = e.comment.nil? ? "#": e.comment
41
+ if e.actual
42
+ @generated.push "#{e.param} = #{e.actual}#{cond} #{comment} [expected #{e.value}]"
43
+ else
44
+ @generated.push "#{e.param} = #{e.value}#{cond} #{comment} [skipped]"
45
+ end
46
+ end
47
+ end
48
+
49
+ def error msg
50
+ @errors.push msg unless @errors.first == msg
51
+ end
52
+
53
+ def messages
54
+ strings = @errors + @mismatches
55
+ return strings.size == 0 ? "": strings.join("\n")
56
+ end
57
+
58
+ def warn msg
59
+ @warns.push msg unless @warns.first == msg
60
+ end
61
+
62
+ def skipcond entry
63
+ @skips.push entry
64
+ end
65
+
66
+ def condfail cond
67
+ return false unless cond
68
+ failures = 0
69
+ reqs = cond.split(/\s*,\s*/)
70
+ reqs.each do |req|
71
+ ok = case var = req.slice!(0)
72
+ when 'k'
73
+ Gem::Requirement.new(req).satisfied_by?(kernel_version)
74
+ when 'v'
75
+ Gem::Requirement.new(req).satisfied_by?(distro_version)
76
+ when 'd'
77
+ op = req.slice!(/^[<>~!=]+/)
78
+ begin
79
+ eval "distro #{op} #{req}"
80
+ rescue Exception => e
81
+ raise ArgumentError.new("entry has condition error: #{e.message}")
82
+ end
83
+ else
84
+ raise ArgumentError.new("entry has invalid condition variable: #{var}")
85
+ end
86
+ failures += 1 unless ok
87
+ end
88
+ return failures > 0
89
+ end
90
+
91
+ def assert_equal expected, actual, msg = ''
92
+ @nparams += 1
93
+ if expected === actual
94
+ STDERR.print "." if @tty
95
+ return 0
96
+ else
97
+ STDERR.print "F" if @tty
98
+ @mismatches.push "#{msg}: Expected #{expected}\n#{" "*(msg.size+4)}Actual #{actual}"
99
+ end
100
+ return 1
101
+ end
102
+
103
+ # Read the entire file and split into sections
104
+ #
105
+ def read_sections handle
106
+ section = Tweek::Section.new(0,'<initial>','','')
107
+ while line = handle.gets
108
+ line.chomp!
109
+ if (line =~ /^=begin/)..(line =~ /^=end/)
110
+ section.push OpenStruct.new( :line => line, :lineno => handle.lineno )
111
+ next
112
+ end
113
+
114
+ comment = line.slice!(/#.*$/)
115
+ if line.empty?
116
+ section.push OpenStruct.new( :line => line, :lineno => handle.lineno, :comment => comment )
117
+ next
118
+ end
119
+
120
+ if /^\s*([A-Z0-9]+)\s*(.*?)\s*$/ =~ line # We've hit a new section
121
+ section.process(self)
122
+ section = Tweek::Section.new(handle.lineno, $1, $2, comment)
123
+ next
124
+ end
125
+
126
+ if /^\s*(.+?)\s*=\s*(.*?)\s*(if\s+(.*))?$/ =~ line
127
+ section.push OpenStruct.new( :lineno => handle.lineno, :param => $1, :value => $2,
128
+ :cond => $4, :comment => comment )
129
+ next
130
+ end
131
+ error "#{handle.lineno}: Unrecognized line: #{line}"
132
+ end
133
+ section.process(self)
134
+
135
+ end
136
+
137
+ def results
138
+ STDERR.puts "\nDistro: #{@distro} Version: #{@distro_version} Kernel: #{@kernel_version}"
139
+ STDERR.puts "\n#{@nparams} parameters checked, #{@skips.size} skipped, #{@mismatches.size} mismatches, #{@warns.size} warnings, #{@errors.size} errors"
140
+ STDERR.puts "\n#{@errors.join("\n")}" unless @errors.empty?
141
+ STDERR.puts "\n#{@warns.join("\n")}" unless @warns.empty?
142
+ STDERR.puts "\n#{@mismatches.join("\n")}" unless @mismatches.empty?
143
+ @generated.each { |l| STDOUT.puts l}
144
+ return @mismatches.size
145
+ end
146
+ end
@@ -0,0 +1,252 @@
1
+ # A section is an array of the parsed lines, each element is an OpenStruct
2
+ # There are the following types of Entry
3
+ # With line attributes - single lines
4
+ # With section type and list attributes
5
+ # With parameter value and conditional attributes
6
+ # All entries may have an optional comment attribute
7
+ #
8
+ class Tweek::Section < Array
9
+
10
+ attr_reader :lineno, :type, :list, :comment
11
+ def initialize lineno, type, list, comment
12
+ @lineno = lineno
13
+ @type = type
14
+ @list = list
15
+ @comment = comment
16
+ end
17
+
18
+ def section_entry
19
+ OpenStruct.new(:lineno => lineno, :type => type, :list => list, :comment => comment )
20
+ end
21
+
22
+ # Iterate through each entry in the section.
23
+ # If it's a comment then pass to the generate method
24
+ # If it has a condition which is not met then pass to generate
25
+ # If it passes yield the entry
26
+ #
27
+ def each_entry cs, &block
28
+ self.each do |entry|
29
+ if entry.line
30
+ cs.generate :line, entry
31
+ next
32
+ end
33
+ begin
34
+ if cs.condfail entry.cond
35
+ cs.generate :entry, entry
36
+ cs.skipcond entry
37
+ next
38
+ end
39
+ yield entry
40
+ rescue Exception => e
41
+ cs.error "#{entry.lineno}: #{e.message}"
42
+ end
43
+ end
44
+ end
45
+
46
+ def process cs
47
+
48
+ cs.generate :section, section_entry unless type == '<initial>'
49
+
50
+ return if self.empty?
51
+
52
+ case type
53
+ when '<initial>'
54
+ each_entry (cs) do |entry|
55
+ end
56
+
57
+ when 'BLKDEV' # BLOCK DEVICE PARAMETERS
58
+
59
+ Dir.chdir('/dev')
60
+ devices = Dir.glob(self.list.split(' ').map{|dev| dev.gsub(/^\/dev\//,'')})
61
+
62
+ cs.warn "Block device check skipped: no devices found" if devices.empty?
63
+
64
+ devices.each do |blk|
65
+ each_entry (cs) do |entry|
66
+ entry.actual = File.open("/sys/block/#{blk}/queue/#{entry.param}", &:read).chomp rescue $!.message
67
+ if entry.param == 'scheduler'
68
+ entry.actual = entry.actual.slice(/\[(.*?)\]/,1) unless entry.actual == 'none'
69
+ end
70
+ cs.assert_equal entry.value, entry.actual, "/dev/#{blk} #{entry.param}"
71
+ cs.generate :entry, entry
72
+ end
73
+ end
74
+
75
+ when 'KERNEL' # KERNEL PARAMETERS
76
+ each_entry (cs) do |entry|
77
+ actual = /\b(#{entry.param})(=\S+)?\b/.match(Tweek::App.bootline)
78
+ case
79
+ when (entry.value == 'true' and actual)
80
+ observed = actual.to_s
81
+ expected = entry.param
82
+ when (entry.value == 'true' and actual.nil?)
83
+ expected = 'to be found'
84
+ observed = 'was not found'
85
+ when (entry.value == 'false' and actual)
86
+ expected = 'to not be found'
87
+ observed = 'was found'
88
+ when (entry.value == 'false' and actual.nil?)
89
+ expected = nil
90
+ observed = nil
91
+ else
92
+ expected = entry.value
93
+ observed = actual.nil? ? 'was not found' : actual[2][1..-1]
94
+ end
95
+ cs.assert_equal expected, observed, "Kernel parameter #{entry.param}"
96
+ entry.actual = !actual.nil?
97
+ cs.generate :entry, entry
98
+ end
99
+
100
+ when 'CLOCKSOURCE'
101
+ each_entry (cs) do |entry|
102
+ entry.actual=File.open("/sys/devices/system/clocksource/#{entry.param}/current_clocksource",&:read).chomp rescue $!.message
103
+ cs.assert_equal entry.value, entry.actual, entry.param
104
+ cs.generate :entry, entry
105
+ end
106
+
107
+ when 'SYSCTL' # SYSCTL SETTINGS
108
+ each_entry (cs) do |entry|
109
+ file = entry.param.gsub(/\./,'/')
110
+ entry.actual = File.open("/proc/sys/#{file}", &:read).chomp.gsub(/\s+/,' ') rescue $!.message
111
+ cs.assert_equal entry.value, entry.actual, entry.param
112
+ cs.generate :entry, entry
113
+ end
114
+
115
+ when 'NET' # NETWORK DEVICES
116
+ devices = self.list.split(' ').map{|dev| dev.gsub(/^\/dev\//,'')}
117
+ cs.warn "Network device check skipped: no devices found" if devices.empty?
118
+
119
+ devices.each do |netdev|
120
+ each_entry (cs) do |entry|
121
+
122
+ case entry.param
123
+ when 'driver'
124
+ entry.actual = File.basename(File.readlink("/sys/class/net/#{netdev}/device/driver"))
125
+ cs.assert_equal entry.value, entry.actual, entry.param
126
+
127
+ when 'irqs'
128
+
129
+ irqs=File.open("/proc/interrupts", &:readlines).grep(/\b#{netdev}\b/).map{|m| m.partition(':')[0].strip}
130
+
131
+ if irqs.empty?
132
+ cs.warn "#{netdev} IRQ check skipped: none found"
133
+ entry.actual = 'null'
134
+ cs.generate :entry, entry
135
+ next
136
+ end
137
+
138
+ ncores = `getconf _NPROCESSORS_ONLN`.chomp.to_i rescue 0
139
+ mismatches = 0
140
+ irqs.each_with_index do |irq, ix|
141
+ case entry.value
142
+ when 'null','none','ignore'
143
+ next
144
+
145
+ when 'aws'
146
+ expected_rps = ("00000000," * 3) + "0000ff00"
147
+ expected_rss = ("00000000," * 3) + sprintf("%08x", 1<<ix)
148
+
149
+ when 'pin'
150
+ case ncores
151
+ when 32 # RPS on cores 10-15 and 18-31, RSS tied to 0-7
152
+ case ix
153
+ when 0..7
154
+ expected_rps = ("00000000," * 3) + "fffefe00"
155
+ expected_rss = ("00000000," * 3) + sprintf("%08x", 1<<(ix+1))
156
+ else
157
+ cs.warn "#{netdev} IRQ strategy '#{entry.value}' can't handle IRQ#{ix}"
158
+ end
159
+
160
+ when 64 # Split the work across the two nodes
161
+ case ix
162
+ when 0..3 # alloc on node 0 (cpus 0-3)
163
+ expected_rps = ("00000000," * 2) + "0000ffff," + "0000ffe0"
164
+ expected_rss = ("00000000," * 3) + sprintf("%08x", 1<<(ix+1))
165
+ when 4..7 # alloc on node 1 (
166
+ expected_rps = ("00000000," * 2) + "ffff0000," + "ffe00000"
167
+ expected_rss = ("00000000," * 3) + sprintf("%08x", 1<<(ix + 9))
168
+ else
169
+ cs.warn "#{netdev} IRQ strategy '#{entry.value}' can't handle IRQ#{ix}"
170
+ end
171
+
172
+ else
173
+ cs.error "#{entry.lineno}: Can't handle #{ncores} cores in IRQ strategy '#{entry.value}'"
174
+ end
175
+
176
+ else
177
+ cs.error "#{entry.lineno}: Unrecognized #{netdev} IRQ strategy '#{entry.value}'"
178
+ end
179
+ actual_rss = File.open("/proc/irq/#{irq}/smp_affinity",&:read).chomp rescue $!.message
180
+ actual_rps = File.open("/sys/class/net/#{netdev}/queues/rx-#{ix}/rps_cpus", &:read).chomp rescue $!.message
181
+ mismatches += cs.assert_equal expected_rss, actual_rss, "#{netdev}_irq_#{irq}_rss"
182
+ mismatches += cs.assert_equal expected_rps, actual_rps, "#{netdev}_irq_#{irq}_rps"
183
+ end
184
+ entry.actual = 'null' if mismatches > 0
185
+
186
+ else # try getting the name
187
+ begin
188
+ entry.actual = File.open("/sys/class/net/#{netdev}/#{entry.param}", &:read).chomp.gsub(/\s+/,' ')
189
+ cs.assert_equal entry.value, entry.actual, entry.param
190
+
191
+ rescue
192
+ cs.error "#{entry.lineno}: Network parameter #{entry.param} not handled: #{$!.message}"
193
+ next
194
+ end
195
+ end
196
+ cs.generate :entry, entry
197
+ end
198
+ end
199
+
200
+ when 'EXT4' # EXT4 filesystems info via `dumpe2fs -h /dev/#{device}`
201
+ mounted = File.open("/proc/mounts", &:readlines).map{|m| m.split(' ')}
202
+ mounts = Dir.glob(self.list.split(' '))
203
+ mounts.each do |mount|
204
+ unless this = mounted.select{|m| (mount == m[0] or mount == m[1]) and m[2] == 'ext4'}.first
205
+ cs.warn "EXT4 path #{mount} is not mounted or is not mounted as ext4"
206
+ next
207
+ end
208
+ device = this[0].gsub('/dev/','')
209
+ optstring = File.open("/proc/fs/ext4/#{device}/options",&:read)
210
+ options = Hash[optstring.scan(/([^=\s]+)=([^=\s,]+)/)] # options a=b
211
+ optstring.split(/\n/).reject{|o| o.index('=')}.each{|o| options[o] = 'true'}
212
+ each_entry (cs) do |entry|
213
+ entry.actual = options[entry.param] || "<not found>"
214
+ cs.assert_equal entry.value, entry.actual, "EXT4 #{mount}: #{entry.param}"
215
+ cs.generate :entry, entry
216
+ end
217
+ end
218
+
219
+ when 'XFS' # XFS filesystems info via `xfs_info`
220
+ # Dynamically via: /proc/fs/xfs/... ?
221
+ mounts = self.list.split(' ')
222
+ if mounts.empty?
223
+ cs.warn "#{self.lineno}: XFS device check skipped: no mountpoints found"
224
+ end
225
+ mounts.each do |mount|
226
+ xfsinfo = `xfs_info #{mount} 2>/dev/null`.chomp
227
+ if $?.exitstatus > 0
228
+ cs.warn "No XFS filesystem at #{mount}"
229
+ each_entry (cs) { |entry| cs.generate :entry, entry }
230
+ next
231
+ end
232
+ data = Hash[xfsinfo.slice!(/^meta-data.*(?=^naming)/m).scan(/([^=\s]+)=([^=\s,]+)/)]
233
+ naming = Hash[xfsinfo.slice!(/^naming.*(?=^log)/m).scan(/([^=\s]+)=([^=\s,]+)/)]
234
+ log = Hash[xfsinfo.slice!(/^log.*(?=^realtime)/m).scan(/([^=\s]+)=([^=\s,]+)/)]
235
+ realtime = Hash[xfsinfo.slice!(/^realtime.*$/m).scan(/([^=\s]+)=([^=\s,]+)/)]
236
+ xfsparms = { 'data' => data, 'naming' => naming, 'log' => log, 'realtime' => realtime }
237
+
238
+ each_entry (cs) do |entry|
239
+ parameter = entry.param.split('.',2)
240
+ entry.actual = xfsparms[parameter[0]][parameter[1]] rescue "<invalid name>"
241
+ cs.assert_equal entry.value, entry.actual, "XFS #{mount}: #{entry.param}"
242
+ cs.generate :entry, entry
243
+ end
244
+ end
245
+
246
+ else
247
+ cs.error "#{self.lineno}: Unknown type #{self.type}"
248
+ end
249
+
250
+ end
251
+ end
252
+
data/lib/tweek/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Tweek
2
- VERSION = "0.0.1"
2
+ VERSION = "0.9.5"
3
3
  end
data/lib/tweek.rb CHANGED
@@ -1,5 +1,3 @@
1
- require "tweek/version"
2
-
3
1
  module Tweek
4
- # Your code goes here...
2
+ # nothing yet
5
3
  end
data/tweek.gemspec CHANGED
@@ -12,8 +12,6 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = %q{Read and compare Linux parameters for performance tweaking}
13
13
  spec.license = "MIT"
14
14
 
15
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
- # to allow pushing to a single host or delete this section to allow pushing to any host.
17
15
  if spec.respond_to?(:metadata)
18
16
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
19
17
  else
@@ -24,8 +22,8 @@ Gem::Specification.new do |spec|
24
22
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
25
23
  f.match(%r{^(test|spec|features)/})
26
24
  end
27
- spec.bindir = "exe"
28
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.bindir = "bin"
26
+ spec.executables = ['tweek']
29
27
  spec.require_paths = ["lib"]
30
28
 
31
29
  spec.add_development_dependency "bundler", "~> 1.15"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tweek
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Townsend
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-14 00:00:00.000000000 Z
11
+ date: 2017-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -55,7 +55,8 @@ dependencies:
55
55
  description:
56
56
  email:
57
57
  - nick.townsend@mac.com
58
- executables: []
58
+ executables:
59
+ - tweek
59
60
  extensions: []
60
61
  extra_rdoc_files: []
61
62
  files:
@@ -68,7 +69,10 @@ files:
68
69
  - Rakefile
69
70
  - bin/console
70
71
  - bin/setup
72
+ - bin/tweek
71
73
  - lib/tweek.rb
74
+ - lib/tweek/app.rb
75
+ - lib/tweek/section.rb
72
76
  - lib/tweek/version.rb
73
77
  - tweek.gemspec
74
78
  homepage: