storcs 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/README.textile +68 -1
- data/lib/storcs/device.rb +8 -17
- data/lib/storcs/parsers/ibm.rb +17 -0
- data/lib/storcs/summable_sizes.rb +33 -0
- data/lib/storcs/version.rb +1 -1
- data/lib/storcs.rb +1 -0
- data/spec/device_spec.rb +6 -0
- data/spec/formatter_spec.rb +2 -0
- data/spec/parsers/df_nas_spec.rb +3 -0
- data/spec/parsers/equalogic_spec.rb +1 -0
- data/spec/parsers/ibm_spec.rb +5 -4
- metadata +4 -3
data/README.textile
CHANGED
@@ -9,6 +9,8 @@ Storcs (STORage Calculation Service) is a gem designed to help you manage centra
|
|
9
9
|
|
10
10
|
Those calulcations are performed on a state file for each device you have. The way you generate the state file depends on the type of the storage system.
|
11
11
|
|
12
|
+
*Calculations are performed in bytes*.
|
13
|
+
|
12
14
|
For the moment, it has only been tested on the following devices :
|
13
15
|
* IBM DS4000 series (tested with a DS3400, a DS4100, a DS4300 and a DS4500)
|
14
16
|
* Equalogic PS5000 and PS6000 series (tested with a PS5000XV and a PS6000)
|
@@ -23,11 +25,72 @@ gem install storcs-*.gem
|
|
23
25
|
|
24
26
|
h2. Parsers
|
25
27
|
|
26
|
-
A parser is an adapter specific to your device. Parser implementation depends on the way you retrieve your storage informations. Basically, it takes a name and a file,
|
28
|
+
A parser is an adapter specific to your device. Parser implementation depends on the way you retrieve your storage informations. Basically, it takes a name and a file, parses the file, and builds a Storcs::Device object based on the parsed informations. For instance:
|
27
29
|
|
28
30
|
bc. parsed = Storcs::Parsers::DfNas.new("my-shiny-nas.example.com", "/path/to/df-k_output.txt")
|
29
31
|
device = parsed.device
|
30
32
|
|
33
|
+
h2. Sizes
|
34
|
+
|
35
|
+
Now that you have a "device", you can use the common methods to retrieve informations on this device :
|
36
|
+
|
37
|
+
bc. device.name
|
38
|
+
=> "my-shiny-nas.example.com"
|
39
|
+
device.used
|
40
|
+
=> 612376576
|
41
|
+
device.size
|
42
|
+
=> 814572544
|
43
|
+
device.free
|
44
|
+
=> 202195968
|
45
|
+
|
46
|
+
ZOMG, a sum and a percentage !!
|
47
|
+
|
48
|
+
Well, ok, that's not so impressive. The interesting part comes when you have nested " " " devices" " ", like in most storage devices on the market : SAN devices have enclosures, and / or raid groups, and / or arrays of disks, etc.
|
49
|
+
|
50
|
+
Let's take an example without parser (parsers do all this magic for you) :
|
51
|
+
|
52
|
+
bc. dev = Storcs::Device.new("my-device")
|
53
|
+
=> #<Storcs::Device:0x9050a9c @name="my-device", @children=[]>
|
54
|
+
array1 = Storcs::Device.new("array1"); array1.real_size=100; array1.real_used=50; array1
|
55
|
+
=> #<Storcs::Device:0x98ee258 @name="array1", @children=[], @real_size=100, @real_used=50>
|
56
|
+
array2 = Storcs::Device.new("array2"); array2.real_size=100; array2.real_used=25; array2
|
57
|
+
=> #<Storcs::Device:0x98e3c7c @name="array2", @children=[], @real_size=100, @real_used=25>
|
58
|
+
dev.children << array1; dev.children << array2
|
59
|
+
=> ...
|
60
|
+
dev.size
|
61
|
+
=> 200
|
62
|
+
dev.used
|
63
|
+
=> 75
|
64
|
+
dev.percent_used
|
65
|
+
=> 37.5
|
66
|
+
|
67
|
+
Imagine you have nested storage "devices", with 3, 4 or 5 levels of recursions, you probably don't want to screw your app with all those calculations.
|
68
|
+
|
69
|
+
One more thing, some parsers may parse and thus provide extra attributes which are not standard / available in others. For instance, IBM parser provides ability to know the RAID type of an array, and the size of unassigned disks:
|
70
|
+
|
71
|
+
bc. ibm_device.childrens.map(&:raid)
|
72
|
+
=> ["5", "1", "5", "5"]
|
73
|
+
ibm_device.unassigned
|
74
|
+
=> 3142530966
|
75
|
+
|
76
|
+
h2. Helper
|
77
|
+
|
78
|
+
storcs gem comes with a helper method to help you format sizes, since everything is calculated in bytes internally and you probably don't want that in your final rendering.
|
79
|
+
|
80
|
+
bc. include Storcs::Formatter
|
81
|
+
pretty_size(1)
|
82
|
+
=> "1.0bytes"
|
83
|
+
pretty_size(12345)
|
84
|
+
=> "12.1Kb"
|
85
|
+
pretty_size(825388561334)
|
86
|
+
=> "768.7Gb"
|
87
|
+
pretty_size(12285713148014)
|
88
|
+
=> "11.2Tb"
|
89
|
+
|
90
|
+
More options can be added on the formatter side on demand.
|
91
|
+
|
92
|
+
h2. Available parsers
|
93
|
+
|
31
94
|
h3. df -k
|
32
95
|
|
33
96
|
This is the simplest parser. It analyzes the output of a @df -Pk@ command on a mounted filesystem, possibly a local filesystem or a NAS attached with NFS or CIFS:
|
@@ -45,3 +108,7 @@ bc. SMcli 192.0.0.15 -c 'show storagesubsystem profile;' > file.txt
|
|
45
108
|
h3. Equalogic PS5000 and PS6000
|
46
109
|
|
47
110
|
It parses the output of a 'show' command in the shell. Unfortunately, I wasn't able to run it remotely since my network administrator didn't allow me. So I have a script based on the "expect" tool with the @show@ command inside.
|
111
|
+
|
112
|
+
h3. Yours!
|
113
|
+
|
114
|
+
If you have a storage device you'd like to see in this list, feel free to open an issue here with at least an example 'profile' file (this can be the output of a command, a plain text or structured file) and the result I should find (used size/total size at least). Maybe somebody else (or me) will be interested in building a parser for your device.
|
data/lib/storcs/device.rb
CHANGED
@@ -1,24 +1,13 @@
|
|
1
1
|
module Storcs
|
2
2
|
class Device
|
3
|
-
|
3
|
+
extend SummableSizes
|
4
|
+
|
5
|
+
attr_accessor :name, :children, :raid
|
6
|
+
summable_sizes :size, :used, :unassigned
|
4
7
|
|
5
8
|
def initialize(name)
|
6
9
|
@name = name
|
7
10
|
@children = []
|
8
|
-
@real_used = nil
|
9
|
-
@real_size = nil
|
10
|
-
end
|
11
|
-
|
12
|
-
def size
|
13
|
-
real_size || children.inject(0) do |memo,child|
|
14
|
-
memo + child.size
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def used
|
19
|
-
real_used || children.inject(0) do |memo,child|
|
20
|
-
memo + child.used
|
21
|
-
end
|
22
11
|
end
|
23
12
|
|
24
13
|
def free
|
@@ -26,11 +15,13 @@ module Storcs
|
|
26
15
|
end
|
27
16
|
|
28
17
|
def percent_used
|
29
|
-
|
18
|
+
return 0 unless size.integer? && size > 0
|
19
|
+
(100 * used.to_f / size).round(2)
|
30
20
|
end
|
31
21
|
|
32
22
|
def percent_free
|
33
|
-
|
23
|
+
return 0 unless size.integer? && size > 0
|
24
|
+
(100 * free.to_f / size).round(2)
|
34
25
|
end
|
35
26
|
end
|
36
27
|
end
|
data/lib/storcs/parsers/ibm.rb
CHANGED
@@ -12,6 +12,7 @@ module Storcs::Parsers
|
|
12
12
|
|
13
13
|
def parse!(content)
|
14
14
|
@device.children = arrays
|
15
|
+
@device.real_unassigned = unassigned
|
15
16
|
end
|
16
17
|
|
17
18
|
def sections
|
@@ -54,5 +55,21 @@ module Storcs::Parsers
|
|
54
55
|
end.compact
|
55
56
|
@arrays
|
56
57
|
end
|
58
|
+
|
59
|
+
def unassigned
|
60
|
+
return @unassigned if @unassigned
|
61
|
+
@unassigned = 0
|
62
|
+
in_unassigned = false
|
63
|
+
sections[:drives].map do |line|
|
64
|
+
if line.match /Unassigned/
|
65
|
+
in_unassigned = true
|
66
|
+
elsif line.match /^\s*$/
|
67
|
+
in_unassigned = false
|
68
|
+
elsif in_unassigned && line.match(/Usable capacity:\s+(.+)$/)
|
69
|
+
@unassigned += parse_size($1)
|
70
|
+
end
|
71
|
+
end.compact
|
72
|
+
@unassigned
|
73
|
+
end
|
57
74
|
end
|
58
75
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Storcs
|
2
|
+
module SummableSizes
|
3
|
+
# Avoids defining recursively summable columns again
|
4
|
+
# and again. Usage:
|
5
|
+
#
|
6
|
+
# class Device
|
7
|
+
# summable_sizes :size, :used, :blah
|
8
|
+
# ...
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# For instance, here's the result for 'used' size:
|
12
|
+
#
|
13
|
+
# def used
|
14
|
+
# real_used || children.inject(0) do |memo,child|
|
15
|
+
# memo + child.used
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
def summable_sizes(*columns)
|
20
|
+
columns.each do |column|
|
21
|
+
class_eval <<-EOF
|
22
|
+
attr_accessor :real_#{column}
|
23
|
+
def #{column}
|
24
|
+
real_#{column} || children.inject(0) do |memo,child|
|
25
|
+
memo + child.#{column}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
EOF
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/lib/storcs/version.rb
CHANGED
data/lib/storcs.rb
CHANGED
data/spec/device_spec.rb
CHANGED
@@ -26,4 +26,10 @@ describe Storcs::Device do
|
|
26
26
|
@bay.percent_used.should == 55
|
27
27
|
@bay.percent_free.should == 45
|
28
28
|
end
|
29
|
+
|
30
|
+
it "ensures a device with no size doesn't screw up on calculations" do
|
31
|
+
device = Storcs::Device.new("bay")
|
32
|
+
device.percent_used.should == 0
|
33
|
+
device.percent_free.should == 0
|
34
|
+
end
|
29
35
|
end
|
data/spec/formatter_spec.rb
CHANGED
data/spec/parsers/df_nas_spec.rb
CHANGED
@@ -8,5 +8,8 @@ describe Storcs::Parsers::DfNas do
|
|
8
8
|
parsed.device.used.should == 612376576
|
9
9
|
parsed.device.size.should == 814572544
|
10
10
|
parsed.device.free.should == 202195968
|
11
|
+
parsed.device.unassigned.should == 0
|
12
|
+
parsed.device.percent_free.should == 24.82
|
13
|
+
parsed.device.percent_used.should == 75.18
|
11
14
|
end
|
12
15
|
end
|
data/spec/parsers/ibm_spec.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
2
|
|
3
3
|
describe Storcs::Parsers::Ibm do
|
4
|
-
models = {"DS4500" => { :num_arrays => 15, :num_sections => 11,
|
5
|
-
:
|
4
|
+
models = {"DS4500" => { :num_arrays => 15, :num_sections => 11, :bay_size => 12285713148014,
|
5
|
+
:bay_used => 11460324586680, :bay_free => 825388561334, :bay_unassigned => 731389980835,
|
6
6
|
:first_array_name => "ARRAY 1", :first_array_raid => "5", :first_array_ld_num => 17,
|
7
7
|
:ld_name => "array1_LUN0_app01_5G", :ld_size => 5368709120,
|
8
8
|
:array_size => 1316496596795, :array_used => 655826473713 },
|
9
|
-
"DS3400" => { :num_arrays => 1, :num_sections => 9,
|
10
|
-
:
|
9
|
+
"DS3400" => { :num_arrays => 1, :num_sections => 9, :bay_size => 2395702692938,
|
10
|
+
:bay_used => 2395702692938, :bay_free => 0, :bay_unassigned => 0,
|
11
11
|
:first_array_name => "ARRAY 1", :first_array_raid => "5", :first_array_ld_num => 2,
|
12
12
|
:ld_name => "SAN01_LUN1", :ld_size => 1099511627776,
|
13
13
|
:array_size => 2395702692938, :array_used => 2395702692938 }
|
@@ -29,6 +29,7 @@ describe Storcs::Parsers::Ibm do
|
|
29
29
|
bay.size.should == @expected[:bay_size]
|
30
30
|
bay.used.should == @expected[:bay_used]
|
31
31
|
bay.free.should == @expected[:bay_free]
|
32
|
+
bay.unassigned.should == @expected[:bay_unassigned]
|
32
33
|
end
|
33
34
|
|
34
35
|
it "divides a profile file into small sections" do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jean-Baptiste Barth
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-03-29 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- lib/storcs/parsers/equalogic.rb
|
53
53
|
- lib/storcs/parsers/ibm.rb
|
54
54
|
- lib/storcs/parsers/utils.rb
|
55
|
+
- lib/storcs/summable_sizes.rb
|
55
56
|
- lib/storcs/version.rb
|
56
57
|
- spec/data/df_nas.txt
|
57
58
|
- spec/data/equalogic_PS5000XV.txt
|