storcs 0.0.1 → 0.0.2

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.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  pkg/*
2
+ tmp/*
2
3
  *.gem
3
4
  .bundle
5
+ .rvmrc
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, parse the file, and build a Storcs::Device object based on the parsed informations. For instance:
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
- attr_accessor :name, :children, :real_used, :real_size, :raid
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
- (100 * used / size).round
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
- (100 * free / size).round
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
@@ -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
+
@@ -1,3 +1,3 @@
1
1
  module Storcs
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/storcs.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'storcs/summable_sizes'
1
2
  require 'storcs/device'
2
3
  require 'storcs/parsers'
3
4
  require 'storcs/formatter'
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
@@ -1,3 +1,5 @@
1
+ require File.expand_path('../spec_helper',__FILE__)
2
+
1
3
  describe Storcs::Formatter do
2
4
  include Storcs::Formatter
3
5
  it "formats sizes in bytes" do
@@ -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
@@ -9,6 +9,7 @@ describe Storcs::Parsers::Equalogic do
9
9
  bay.size.should == 4020012968837
10
10
  bay.used.should == 3972897177600
11
11
  bay.free.should == 47115791237
12
+ bay.unassigned.should == 0
12
13
  end
13
14
 
14
15
  it "divides the bay into a set of logical volumes" do
@@ -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
- :bay_size => 12285713148014, :bay_used => 11460324586680, :bay_free => 825388561334,
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
- :bay_size => 2395702692938, :bay_used => 2395702692938, :bay_free => 0,
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
- - 1
9
- version: 0.0.1
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-01-06 00:00:00 +01:00
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