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 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