otakumike-ruby-lvm 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 364fa0210d78fe3efb61f86287b05c87ad52126c
4
+ data.tar.gz: 3bf6344d02f0cfa8ae09bce3b2517b6c6feb975a
5
+ SHA512:
6
+ metadata.gz: 4bdfd0b5a9bb0b373009733ad5cb34b7ddcc8a171f8f883dfe22c8af1e82aeb2ded4ba3978fd9e2ea7de40364aa14bc7b8fd44c64bf7eca6c96672a9379580f6
7
+ data.tar.gz: 306d3426dda73bd978320cd77a86eda36a42e31474d00cab6ee05cc8abfa9344e42b8e9cac8e25f716defaea115029d510ed59b5546fe3ebcbbed2e2e7dc9f32
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/History.txt ADDED
@@ -0,0 +1,14 @@
1
+ === 0.1.1 / 2008-07-21
2
+
3
+ * 1 major enhancement
4
+ * A complete rewrite! We won't bother attempting to wrap complex lvm
5
+ operations, but instead provide LVM.raw() command. The wrapper now focuses
6
+ purely on translating lvm lv/vg/pv data into the most useful ruby objects
7
+ possible. The arguments passed to the underlying binaries have been broken
8
+ out into a ruby-lvm-attributes package.
9
+
10
+ === 0.0.1 / 2008-05-28
11
+
12
+ * 1 major enhancement
13
+ * Birthday!
14
+ * Test release.
data/README.txt ADDED
@@ -0,0 +1,77 @@
1
+ = ruby-lvm
2
+
3
+ * http://ruby-lvm.rubyforge.org
4
+ * mailto:mkent@magoazul.com
5
+
6
+ == DESCRIPTION:
7
+ This is a fork of the ruby-lvm gem found at git://rubyforge.org/ruby-lvm.git.
8
+ The primary difference from upstream is that it depends on
9
+ di-ruby-lvm-attributes instead of ruby-lvm-attributes. This adds support for lvm
10
+ version 2.02.66(2).
11
+
12
+
13
+ This is a wrapper for the LVM2 administration utility, lvm. Its primary
14
+ function it to convert physical volumes, logical volumes and volume groups
15
+ into easy to use ruby objects. It also provides a simple wrapper for typical
16
+ create/delete/etc operations.
17
+
18
+ Due to a lack of LVM2 api this is a best effort attempt at ruby integration but
19
+ subject to complete replacement in the future.
20
+
21
+ == FEATURES/PROBLEMS:
22
+
23
+ * Exposes all possible data from the lvs/vgs/pvs commands. Data is grouped
24
+ sensibly (I hope).
25
+ * Doesn't nicely wrap creation/deletion/etc operations, they must be created
26
+ by hand and passed as raw commands.
27
+
28
+ == SYNOPSIS:
29
+
30
+ require 'lvm'
31
+
32
+ LVM::LVM.new({:command => "/usr/bin/sudo /sbin/lvm"}) do |lvm|
33
+ puts "lvm version: #{lvm.version}\n"
34
+
35
+ lvm.volume_groups.each do |vg|
36
+ puts "vg: #{vg.name}"
37
+ end
38
+ end
39
+
40
+ == REQUIREMENTS:
41
+
42
+ * di-ruby-lvm-attributes
43
+ * popen4
44
+
45
+ == INSTALL:
46
+
47
+ * sudo gem install di-ruby-lvm
48
+
49
+ == FEEDBACK:
50
+
51
+ Please feel free to submit patches or constructive criticism, I'm still pretty
52
+ new to ruby and object oriented programming in general.
53
+
54
+ == LICENSE:
55
+
56
+ (The MIT License)
57
+
58
+ Copyright (c) 2008 Matthew Kent, Bravenet Web Services Inc.
59
+
60
+ Permission is hereby granted, free of charge, to any person obtaining
61
+ a copy of this software and associated documentation files (the
62
+ 'Software'), to deal in the Software without restriction, including
63
+ without limitation the rights to use, copy, modify, merge, publish,
64
+ distribute, sublicense, and/or sell copies of the Software, and to
65
+ permit persons to whom the Software is furnished to do so, subject to
66
+ the following conditions:
67
+
68
+ The above copyright notice and this permission notice shall be
69
+ included in all copies or substantial portions of the Software.
70
+
71
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
72
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
73
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
74
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
75
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
76
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
77
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Todo.txt ADDED
@@ -0,0 +1,9 @@
1
+ = to do
2
+
3
+ == 0.2.1
4
+ * basic test suite, how?
5
+
6
+ == 0.1.2
7
+ * test on more distributions!
8
+ * more documentation.
9
+ * debug mode, logger?
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Demonstration of the creation of an lvm snapshot, using sudo, and reading its
4
+ # attributes.
5
+
6
+ $: << File.dirname(__FILE__) + "/../lib"
7
+
8
+ require 'lvm'
9
+
10
+ vol = "sys.vg/tmp.lv"
11
+ snap = "demo_snap"
12
+
13
+ lvm = LVM::LVM.new(:command => "/usr/bin/sudo /sbin/lvm")
14
+
15
+ if lvm.logical_volumes[snap]
16
+ puts "#{snap} exists! Remove it"
17
+ exit(1)
18
+ end
19
+
20
+ lvm.raw("lvcreate --snapshot --size 10M --name #{snap} #{vol}")
21
+ lv = lvm.logical_volumes[snap]
22
+
23
+ out=<<msg
24
+ snapshot of #{vol}, #{snap}, created
25
+ - uuid: #{lv.uuid}
26
+ - major,minor: #{lv.kernel_major},#{lv.kernel_minor}
27
+ msg
28
+ puts out
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Demonstration of the exception handling with raw commands.
4
+
5
+ $: << File.dirname(__FILE__) + "/../lib"
6
+
7
+ require 'lvm'
8
+
9
+ lvm = LVM::LVM.new(:command => "/usr/bin/sudo /sbin/lvm")
10
+
11
+ begin
12
+ lvm.raw("--blah blah")
13
+ rescue LVM::External::ExternalFailure => error
14
+ puts "Raw operation failed with [#{error}]"
15
+ end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # A more advanced demonstration displaying a complete overview of the current
4
+ # lvm configuration.
5
+
6
+ $: << File.dirname(__FILE__) + "/../lib"
7
+
8
+ require 'lvm'
9
+
10
+ LVM::LVM.new({:command => "/usr/bin/sudo /sbin/lvm"}) do |lvm|
11
+ puts "lvm version: #{lvm.version}\n"
12
+
13
+ puts "\nlogical view"
14
+ puts "------------"
15
+ lvm.volume_groups.each do |vg|
16
+ puts "vg: #{vg.name}"
17
+ vg.logical_volumes.each do |lv|
18
+ puts " lv: #{lv.name} #{lv.size}"
19
+ lv.segments.each do |lvseg|
20
+ puts " lvseg: #{lvseg.devices} ##{lv.segments.index(lvseg)} #{lvseg.start} - #{lvseg.finish} = #{lvseg.size}"
21
+ end
22
+ if lv.snapshot?
23
+ puts " snapshot origin: #{lv.origin}"
24
+ end
25
+ end
26
+ end
27
+
28
+ puts "\nphysical view"
29
+ puts "-------------"
30
+ lvm.volume_groups.each do |vg|
31
+ puts "vg: #{vg.name}"
32
+ vg.physical_volumes.each do |pv|
33
+ puts " pv: #{pv.name}"
34
+ pv.segments.each do |pvseg|
35
+ puts " pvseg: ##{pv.segments.index(pvseg)} #{pvseg.start} - #{pvseg.finish}"
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'open4'
3
+
4
+ module LVM
5
+ module External
6
+ class ExternalFailure < RuntimeError; end
7
+
8
+ def cmd(cmd)
9
+ output = []
10
+ error = nil
11
+ stat = Open4.popen4(cmd) do |pid, stdin, stdout, stderr|
12
+ while line = stdout.gets
13
+ output << line
14
+ end
15
+ error = stderr.read.strip
16
+ end
17
+ if stat.exited?
18
+ if stat.exitstatus > 0
19
+ raise ExternalFailure, "Fatal error, `#{cmd}` returned #{stat.exitstatus} with '#{error}'"
20
+ end
21
+ elsif stat.signaled?
22
+ raise ExternalFailure, "Fatal error, `#{cmd}` got signal #{stat.termsig} and terminated"
23
+ elsif stat.stopped?
24
+ raise ExternalFailure, "Fatal error, `#{cmd}` got signal #{stat.stopsig} and is stopped"
25
+ end
26
+
27
+ if block_given?
28
+ return output.each { |l| yield l }
29
+ else
30
+ return output.join
31
+ end
32
+ end
33
+ module_function :cmd
34
+
35
+ end # module External
36
+ end # module LVM
@@ -0,0 +1,9 @@
1
+ require 'ostruct'
2
+
3
+ module LVM
4
+ class LogicalVolume < OpenStruct
5
+ # Helpers
6
+ def open?; device_open; end
7
+ def snapshot?; volume_type == :snapshot ? true : false; end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ require 'ostruct'
2
+
3
+ module LVM
4
+ class LogicalVolumeSegment < OpenStruct; end
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'lvm/volumes'
2
+ require 'lvm/wrapper/lvs'
3
+ require 'lvm/wrapper/lvsseg'
4
+
5
+ module LVM
6
+ class LogicalVolumes
7
+ include Enumerable
8
+
9
+ include Volumes
10
+ include Wrapper
11
+
12
+ def initialize(options)
13
+ @lvs = LVS.new(options)
14
+ @lvsseg = LVSSEG.new(options)
15
+ end
16
+
17
+ # Gather all information about logical volumes.
18
+ #
19
+ # See VolumeGroups.each for a better representation of LVM data.
20
+ def each
21
+ lvs = @lvs.list
22
+ lvsseg = @lvsseg.list
23
+
24
+ lvs.each do |lv|
25
+ lv.segments = lvsseg.select { |seg| seg.lv_uuid == lv.uuid }
26
+ yield lv
27
+ end
28
+ end
29
+
30
+ def list
31
+ self.each { }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ require 'ostruct'
2
+
3
+ module LVM
4
+ class PhysicalVolume < OpenStruct; end
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'ostruct'
2
+
3
+ module LVM
4
+ class PhysicalVolumeSegment < OpenStruct; end
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'lvm/volumes'
2
+ require 'lvm/wrapper/pvs'
3
+ require 'lvm/wrapper/pvsseg'
4
+
5
+ module LVM
6
+ class PhysicalVolumes
7
+ include Enumerable
8
+
9
+ include Volumes
10
+ include Wrapper
11
+
12
+ def initialize(options)
13
+ @pvs = PVS.new(options)
14
+ @pvsseg = PVSSEG.new(options)
15
+ end
16
+
17
+ # Gather all information about physical volumes.
18
+ #
19
+ # See VolumeGroups.each for a better representation of LVM data.
20
+ def each
21
+ pvs = @pvs.list
22
+ pvsseg = @pvsseg.list
23
+
24
+ pvs.each do |pv|
25
+ pv.segments = pvsseg.select { |seg| seg.pv_uuid == pv.uuid }
26
+ yield pv
27
+ end
28
+ end
29
+
30
+ def list
31
+ self.each { }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ require 'ostruct'
2
+
3
+ module LVM
4
+ class UserLand < OpenStruct; end
5
+ end
@@ -0,0 +1,3 @@
1
+ module LVM
2
+ VERSION = '0.2.1'
3
+ end
@@ -0,0 +1,5 @@
1
+ require 'ostruct'
2
+
3
+ module LVM
4
+ class VolumeGroup < OpenStruct; end
5
+ end
@@ -0,0 +1,39 @@
1
+ require 'lvm/volumes'
2
+ require 'lvm/logical_volumes'
3
+ require 'lvm/physical_volumes'
4
+ require 'lvm/wrapper/vgs'
5
+
6
+ module LVM
7
+ class VolumeGroups
8
+ include Enumerable
9
+
10
+ include Volumes
11
+ include Wrapper
12
+
13
+ def initialize(options)
14
+ @vgs = VGS.new(options)
15
+ @pvs = PhysicalVolumes.new(options)
16
+ @lvs = LogicalVolumes.new(options)
17
+ end
18
+
19
+ # Gather all information about volume groups and their underlying
20
+ # logical and physical volumes.
21
+ #
22
+ # This is the best representation of LVM data.
23
+ def each
24
+ vgs = @vgs.list
25
+ lvs = @lvs.list
26
+ pvs = @pvs.list
27
+
28
+ vgs.each do |vg|
29
+ vg.logical_volumes = lvs.select { |lv| lv.vg_uuid == vg.uuid }
30
+ vg.physical_volumes = pvs.select { |pv| pv.vg_uuid == vg.uuid }
31
+ yield vg
32
+ end
33
+ end
34
+
35
+ def list
36
+ self.each { }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+ module LVM
2
+ module Volumes
3
+
4
+ def [](name)
5
+ each {|o| return o if o.name == name}
6
+ return nil
7
+ end
8
+
9
+ def to_s
10
+ x = []
11
+ each {|o| x << o.name}
12
+ return x.join(" ")
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module LVM
2
+ module Wrapper
3
+ module Reporting
4
+ module Constants
5
+ SEPERATOR = '^'
6
+ BASE_ARGUMENTS = "--verbose --separator=#{SEPERATOR} --noheadings --nosuffix --units=b --unbuffered --options %s"
7
+ EMPTY = '-'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,127 @@
1
+ require 'lvm/wrapper'
2
+ require 'lvm/logical_volume'
3
+
4
+ module LVM
5
+ module Wrapper
6
+ class LVS
7
+ include Reporting
8
+
9
+ attr_reader :attributes
10
+ attr_reader :command
11
+
12
+ def initialize(options)
13
+ @attributes = Attributes.load(options[:version], ATTRIBUTES_FILE)
14
+ @command = "#{options[:command]} #{Reporting.build_command(attributes, BASE_COMMAND)}"
15
+ end
16
+
17
+ BASE_COMMAND = "lvs #{Reporting::BASE_ARGUMENTS}"
18
+ ATTRIBUTES_FILE = 'lvs.yaml'
19
+
20
+ # lv_attr attribute handling constants
21
+ # roughly by order referenced in lib/report/report.c:292 (_lvstatus_disp)
22
+ #
23
+ VOLUME_TYPE = {
24
+ 'p' => :pvmove,
25
+ 'c' => :conversion,
26
+ 'M' => :mirror_not_synced,
27
+ 'm' => :mirror,
28
+ 'i' => :mirror_image,
29
+ 'I' => :mirror_image_not_synced,
30
+ 'l' => :mirror_log,
31
+ 'v' => :virtual,
32
+ 'o' => :origin,
33
+ 's' => :snapshot,
34
+ 'S' => :invalid_snapshot,
35
+ # custom, empty is a standard volume
36
+ '-' => :normal
37
+ }
38
+ PERMISSIONS = {
39
+ 'w' => :writeable,
40
+ 'r' => :readonly,
41
+ # custom, from reading source
42
+ '-' => :locked_by_pvmove,
43
+ }
44
+ ALLOCATION_POLICY = {
45
+ 'c' => :contiguous,
46
+ 'l' => :cling,
47
+ 'n' => :normal,
48
+ 'a' => :anywhere,
49
+ 'i' => :inherited,
50
+ 'C' => :contiguous_locked,
51
+ 'L' => :cling_locked,
52
+ 'N' => :normal_locked,
53
+ 'A' => :anywhere_locked,
54
+ 'I' => :inherited_locked
55
+ }
56
+ FIXED_MINOR = {
57
+ # code says its a boolean
58
+ 'm' => true
59
+ }
60
+ STATE = {
61
+ 's' => :suspended,
62
+ 'a' => :active,
63
+ 'i' => :inactive_with_table,
64
+ 'd' => :inactive_without_table,
65
+ 'S' => :suspended_snapshot,
66
+ 'I' => :invalid_snapshot
67
+ }
68
+ DEVICE_OPEN = {
69
+ # code says its a boolean
70
+ 'o' => true
71
+ }
72
+
73
+ def list
74
+ output = External.cmd(@command)
75
+ data = parse(output)
76
+ if block_given?
77
+ return data.each { |obj| yield obj }
78
+ else
79
+ return data
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def parse_lv_attr(lv_attr) #:nodoc:
86
+ translated = {}
87
+ # translate them into nice symbols and a couple booleans
88
+ translated[:volume_type] = VOLUME_TYPE[lv_attr[0].chr]
89
+ translated[:permissions] = PERMISSIONS[lv_attr[1].chr]
90
+ translated[:allocation_policy] = ALLOCATION_POLICY[lv_attr[2].chr]
91
+ translated[:fixed_minor] = FIXED_MINOR[lv_attr[3].chr] ? true : false
92
+ translated[:state] = STATE[lv_attr[4].chr]
93
+ translated[:device_open] = DEVICE_OPEN[lv_attr[5].chr] ? true : false
94
+
95
+ return translated
96
+ end
97
+
98
+ # Parses the output of self.command
99
+ def parse(output) #:nodoc:
100
+ volumes = []
101
+
102
+ output.split("\n").each do |line|
103
+ args = Reporting.process_line(attributes, line)
104
+
105
+ # now we force some types to ints since we've requested them as bytes
106
+ # without a suffix
107
+ args[:size] = args[:size].to_i
108
+
109
+ # we resolve the attributes line to nicer symbols
110
+ args.merge!(parse_lv_attr(args[:attr]))
111
+
112
+ # finally build our object
113
+ volume = LogicalVolume.new(args)
114
+
115
+ if block_given?
116
+ yield volume
117
+ else
118
+ volumes << volume
119
+ end
120
+ end
121
+
122
+ return volumes
123
+ end # parse
124
+
125
+ end # class LVS
126
+ end # module Wrapper
127
+ end # module LVM
@@ -0,0 +1,59 @@
1
+ require 'lvm/wrapper'
2
+ require 'lvm/logical_volume_segment'
3
+
4
+ module LVM
5
+ module Wrapper
6
+ # segment output is very different in that its multi line, easier to treat as own command
7
+ class LVSSEG
8
+ include Reporting
9
+
10
+ attr_reader :attributes
11
+ attr_reader :command
12
+
13
+ def initialize(options)
14
+ @attributes = Attributes.load(options[:version], ATTRIBUTES_FILE)
15
+ @command = "#{options[:command]} #{Reporting.build_command(attributes, BASE_COMMAND)}"
16
+ end
17
+
18
+ BASE_COMMAND = "lvs #{Reporting::BASE_ARGUMENTS}"
19
+ ATTRIBUTES_FILE = 'lvsseg.yaml'
20
+
21
+ def list
22
+ output = External.cmd(@command)
23
+ data = parse(output)
24
+ if block_given?
25
+ return data.each { |obj| yield obj }
26
+ else
27
+ return data
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # Parses the output of self.command
34
+ def parse(output)
35
+ volumes = []
36
+
37
+ output.split("\n").each do |line|
38
+ args = process_line(attributes, line)
39
+
40
+ args[:finish] = args[:start] + args[:size]
41
+
42
+ # finally build our object
43
+ volume = LogicalVolumeSegment.new(args)
44
+
45
+ if block_given?
46
+ yield volume
47
+ else
48
+ volumes << volume
49
+ end
50
+ end
51
+
52
+ return volumes
53
+ end # parse
54
+
55
+ end # class LVSSEG
56
+ end # module Wrapper
57
+ end # module LVM
58
+
59
+
@@ -0,0 +1,84 @@
1
+ require 'lvm/wrapper'
2
+ require 'lvm/physical_volume'
3
+
4
+ module LVM
5
+ module Wrapper
6
+ class PVS
7
+ include Reporting
8
+
9
+ attr_reader :attributes
10
+ attr_reader :command
11
+
12
+ def initialize(options)
13
+ @attributes = Attributes.load(options[:version], ATTRIBUTES_FILE)
14
+ @command = "#{options[:command]} #{Reporting.build_command(attributes, BASE_COMMAND)}"
15
+ end
16
+
17
+ BASE_COMMAND = "pvs #{Reporting::BASE_ARGUMENTS}"
18
+ ATTRIBUTES_FILE = 'pvs.yaml'
19
+
20
+ # pv_attr attribute handling constants
21
+ # roughly by order referenced in lib/report/report.c:360 (_pvstatus_disp)
22
+ #
23
+ ALLOCATABLE = {
24
+ # code says its a boolean
25
+ 'a' => true
26
+ }
27
+ EXPORTED = {
28
+ # code says its a boolean
29
+ 'x' => true
30
+ }
31
+
32
+ def list
33
+ output = External.cmd(@command)
34
+ data = parse(output)
35
+ if block_given?
36
+ return data.each { |obj| yield obj }
37
+ else
38
+ return data
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def parse_pv_attr(pv_attr) #:nodoc:
45
+ translated = {}
46
+ # translate them into nice symbols and a couple booleans
47
+ translated[:allocatable] = ALLOCATABLE[pv_attr[0].chr] ? true : false
48
+ translated[:exported] = EXPORTED[pv_attr[1].chr] ? true : false
49
+
50
+ return translated
51
+ end
52
+
53
+ # Parses the output of self.command
54
+ def parse(output)
55
+ volumes = []
56
+
57
+ output.split("\n").each do |line|
58
+ args = process_line(attributes, line)
59
+
60
+ # now we force some types to ints since we've requested them as bytes
61
+ # without a suffix
62
+ args[:size] = args[:size].to_i
63
+
64
+ # we resolve the attributes line to nicer symbols
65
+ args.merge!(parse_pv_attr(args[:attr]))
66
+
67
+ # finally build our object
68
+ volume = PhysicalVolume.new(args)
69
+
70
+ if block_given?
71
+ yield volume
72
+ else
73
+ volumes << volume
74
+ end
75
+ end
76
+
77
+ return volumes
78
+ end # parse
79
+
80
+ end # class PVS
81
+ end # module Wrapper
82
+ end # module LVM
83
+
84
+
@@ -0,0 +1,57 @@
1
+ require 'lvm/wrapper'
2
+ require 'lvm/physical_volume_segment'
3
+
4
+ module LVM
5
+ module Wrapper
6
+ # segment output is very different in that its multi line, easier to treat as own command
7
+ class PVSSEG
8
+ include Reporting
9
+
10
+ attr_reader :attributes
11
+ attr_reader :command
12
+
13
+ def initialize(options)
14
+ @attributes = Attributes.load(options[:version], ATTRIBUTES_FILE)
15
+ @command = "#{options[:command]} #{Reporting.build_command(attributes, BASE_COMMAND)}"
16
+ end
17
+
18
+ BASE_COMMAND = "pvs #{Reporting::BASE_ARGUMENTS}"
19
+ ATTRIBUTES_FILE = 'pvsseg.yaml'
20
+
21
+ def list
22
+ output = External.cmd(@command)
23
+ data = parse(output)
24
+ if block_given?
25
+ return data.each { |obj| yield obj }
26
+ else
27
+ return data
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # Parses the output of self.command
34
+ def parse(output)
35
+ volumes = []
36
+
37
+ output.split("\n").each do |line|
38
+ args = process_line(attributes, line)
39
+
40
+ args[:finish] = args[:start] + args[:size]
41
+
42
+ # finally build our object
43
+ volume = PhysicalVolumeSegment.new(args)
44
+
45
+ if block_given?
46
+ yield volume
47
+ else
48
+ volumes << volume
49
+ end
50
+ end
51
+
52
+ return volumes
53
+ end # parse
54
+
55
+ end # class PVSSEG
56
+ end # module Wrapper
57
+ end # module LVM
@@ -0,0 +1,112 @@
1
+ require 'lvm/wrapper'
2
+ require 'lvm/volume_group'
3
+
4
+ module LVM
5
+ module Wrapper
6
+ class VGS
7
+ include Reporting
8
+
9
+ attr_reader :attributes
10
+ attr_reader :command
11
+
12
+ def initialize(options)
13
+ @attributes = Attributes.load(options[:version], ATTRIBUTES_FILE)
14
+ @command = "#{options[:command]} #{Reporting.build_command(attributes, BASE_COMMAND)}"
15
+ end
16
+
17
+ BASE_COMMAND = "vgs #{Reporting::BASE_ARGUMENTS}"
18
+ ATTRIBUTES_FILE = 'vgs.yaml'
19
+
20
+ # vg_attr attribute handling constants
21
+ # roughly by order referenced in lib/report/report.c:360 (_vgstatus_disp)
22
+ #
23
+ PERMISSIONS = {
24
+ 'w' => :writeable,
25
+ 'r' => :readonly,
26
+ }
27
+ RESIZEABLE = {
28
+ # code says its a boolean
29
+ 'z' => true
30
+ }
31
+ EXPORTED = {
32
+ # code says its a boolean
33
+ 'x' => true
34
+ }
35
+ PARTIAL = {
36
+ # code says its a boolean
37
+ 'p' => true
38
+ }
39
+ ALLOCATION_POLICY = {
40
+ 'c' => :contiguous,
41
+ 'l' => :cling,
42
+ 'n' => :normal,
43
+ 'a' => :anywhere,
44
+ 'i' => :inherited,
45
+ 'C' => :contiguous_locked,
46
+ 'L' => :cling_locked,
47
+ 'N' => :normal_locked,
48
+ 'A' => :anywhere_locked,
49
+ 'I' => :inherited_locked
50
+ }
51
+ CLUSTERED = {
52
+ # code says its a boolean
53
+ 'c' => true
54
+ }
55
+
56
+ def list
57
+ output = External.cmd(@command)
58
+ data = parse(output)
59
+ if block_given?
60
+ return data.each { |obj| yield obj }
61
+ else
62
+ return data
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def parse_vg_attr(vg_attr) #:nodoc:
69
+ translated = {}
70
+ # translate them into nice symbols and a couple booleans
71
+ translated[:permissions] = PERMISSIONS[vg_attr[0].chr]
72
+ translated[:resizeable] = RESIZEABLE[vg_attr[1].chr] ? true : false
73
+ translated[:exported] = EXPORTED[vg_attr[2].chr] ? true : false
74
+ translated[:partial] = PARTIAL[vg_attr[3].chr] ? true : false
75
+ translated[:allocation_policy] = ALLOCATION_POLICY[vg_attr[4].chr]
76
+ translated[:clustered] = CLUSTERED[vg_attr[5].chr] ? true : false
77
+
78
+ return translated
79
+ end
80
+
81
+ # Parses the output of self.command
82
+ def parse(output) #:nodoc:
83
+ volumes = []
84
+
85
+ output.split("\n").each do |line|
86
+ args = process_line(attributes, line)
87
+
88
+ # now we force some types to ints since we've requested them as bytes
89
+ # without a suffix
90
+ args[:size] = args[:size].to_i
91
+
92
+ # we resolve the attributes line to nicer symbols
93
+ args.merge!(parse_vg_attr(args[:attr]))
94
+
95
+ # finally build our object
96
+ volume = VolumeGroup.new(args)
97
+
98
+ if block_given?
99
+ yield volume
100
+ else
101
+ volumes << volume
102
+ end
103
+ end
104
+
105
+ return volumes
106
+ end # parse
107
+
108
+ end # class VGS
109
+ end # module Wrapper
110
+ end # module LVM
111
+
112
+
@@ -0,0 +1,53 @@
1
+ require 'lvm/attributes'
2
+ require 'lvm/external'
3
+ require 'lvm/wrapper/constants'
4
+
5
+ module LVM
6
+ module Wrapper
7
+ module Reporting
8
+ include Constants
9
+
10
+ # Breakdown return values into attribute => value hash suitable for
11
+ # OpenStruct
12
+ def process_line(expected_attributes, line) #:nodoc:
13
+ line.strip!
14
+ values = line.split(SEPERATOR)
15
+ # nil is easier
16
+ values.map! { |v| (v.empty?) ? nil : v }
17
+
18
+ attributes = {}
19
+ # values and expected attributes are in the same order
20
+ values.size.times do |i|
21
+ value = values[i]
22
+ attribute = expected_attributes[i]
23
+
24
+ name = attribute[:method].to_sym
25
+
26
+ # use hints for type conversion
27
+ case attribute[:type_hint]
28
+ when "String"
29
+ when "Integer"
30
+ value = value.to_i
31
+ when "Float"
32
+ value = value.to_f
33
+ end
34
+ attributes[name] = value
35
+ end
36
+
37
+ return attributes
38
+ end
39
+ module_function :process_line
40
+
41
+ def build_command(expected_attributes, base)
42
+ opts = []
43
+ expected_attributes.each do |a|
44
+ opts << a[:column]
45
+ end
46
+
47
+ return base % opts.join(",")
48
+ end
49
+ module_function :build_command
50
+
51
+ end # module Reporting
52
+ end # module Wrapper
53
+ end # module LVM
data/lib/lvm.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'lvm/external'
2
+ require 'lvm/userland'
3
+ require 'lvm/logical_volumes'
4
+ require 'lvm/volume_groups'
5
+ require 'lvm/physical_volumes'
6
+ require 'lvm/version'
7
+
8
+ module LVM
9
+ class LVM
10
+ attr_reader :command
11
+ attr_reader :logical_volumes
12
+ attr_reader :volume_groups
13
+ attr_reader :physical_volumes
14
+
15
+ VALID_OPTIONS = [
16
+ :command,
17
+ :version,
18
+ :debug
19
+ ]
20
+
21
+ DEFAULT_COMMAND = '/sbin/lvm'
22
+
23
+ def initialize(options={})
24
+ # handy, thanks net-ssh!
25
+ invalid_options = options.keys - VALID_OPTIONS
26
+ if invalid_options.any?
27
+ raise ArgumentError, "invalid option(s): #{invalid_options.join(', ')}"
28
+ end
29
+
30
+ @command = options[:command] || DEFAULT_COMMAND
31
+
32
+ # default to loading attributes for the current version
33
+ options[:version] ||= version
34
+ options[:debug] ||= false
35
+
36
+ @logical_volumes = LogicalVolumes.new(options)
37
+ @volume_groups = VolumeGroups.new(options)
38
+ @physical_volumes = PhysicalVolumes.new(options)
39
+
40
+ if block_given?
41
+ yield self
42
+ else
43
+ return self
44
+ end
45
+ end
46
+
47
+ def raw(args)
48
+ output = []
49
+ External.cmd("#{@command} #{args}") do |line|
50
+ output << line
51
+ end
52
+ if block_given?
53
+ return output.each { |l| yield l }
54
+ else
55
+ return output.join
56
+ end
57
+ end
58
+
59
+ def version
60
+ %r{^(.*?)(-| )}.match(userland.lvm_version)[1]
61
+ end
62
+
63
+ # helper methods
64
+ def userland
65
+ userland = UserLand.new
66
+ raw('version') do |line|
67
+ case line
68
+ when %r{^\s+LVM version:\s+([0-9].*)$}
69
+ userland.lvm_version = $1
70
+ when %r{^\s+Library version:\s+([0-9].*)$}
71
+ userland.library_version = $1
72
+ when %r{^\s+Driver version:\s+([0-9].*)$}
73
+ userland.driver_version = $1
74
+ end
75
+ end
76
+
77
+ return userland
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,26 @@
1
+ $:.unshift(File.expand_path('../lib/', __FILE__))
2
+ require 'lvm/version'
3
+
4
+ deps = {
5
+ 'open4' => [ '~> 0.9', '>= 0.9.6' ],
6
+ 'otakumike-ruby-lvm-attrib' => ['~> 0.0.3']
7
+ }
8
+
9
+ Gem::Specification.new do |gem|
10
+ gem.authors = ["Greg Symons", "Matthew Kent", "Mike Richardson"]
11
+ gem.email = ["mkent@magoazul.com", 'gsymons@gsconsulting.biz', 'mail@mikerichardson.com.au']
12
+ gem.description = %q{A wrapper for the LVM2 administration utility, lvm. Forked for LVM 2.02.166 ONLY}
13
+ gem.license = "MIT"
14
+ gem.summary = %q{A wrapper for the LVM2 administration utility, lvm. Forked for LVM 2.02.166 ONLY}
15
+ gem.homepage = "https://github.com/otakumike/otakumike-ruby-lvm"
16
+ gem.files = `git ls-files`.split($\)
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.name = "otakumike-ruby-lvm"
19
+ gem.require_paths = ["lib"]
20
+ gem.version = LVM::VERSION
21
+
22
+ deps.each do |dep, constraints|
23
+ gem.add_runtime_dependency dep, *constraints
24
+ end
25
+ end
26
+
data/test/test_lvm.rb ADDED
File without changes
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: otakumike-ruby-lvm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Greg Symons
8
+ - Matthew Kent
9
+ - Mike Richardson
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2016-11-09 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: open4
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '0.9'
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.9.6
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - "~>"
30
+ - !ruby/object:Gem::Version
31
+ version: '0.9'
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.9.6
35
+ - !ruby/object:Gem::Dependency
36
+ name: otakumike-ruby-lvm-attrib
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.0.3
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 0.0.3
49
+ description: A wrapper for the LVM2 administration utility, lvm. Forked for LVM 2.02.166
50
+ ONLY
51
+ email:
52
+ - mkent@magoazul.com
53
+ - gsymons@gsconsulting.biz
54
+ - mail@mikerichardson.com.au
55
+ executables: []
56
+ extensions: []
57
+ extra_rdoc_files: []
58
+ files:
59
+ - ".gitignore"
60
+ - History.txt
61
+ - README.txt
62
+ - Todo.txt
63
+ - examples/create_snapshot.rb
64
+ - examples/error_handling.rb
65
+ - examples/show_lvm_config.rb
66
+ - lib/lvm.rb
67
+ - lib/lvm/external.rb
68
+ - lib/lvm/logical_volume.rb
69
+ - lib/lvm/logical_volume_segment.rb
70
+ - lib/lvm/logical_volumes.rb
71
+ - lib/lvm/physical_volume.rb
72
+ - lib/lvm/physical_volume_segment.rb
73
+ - lib/lvm/physical_volumes.rb
74
+ - lib/lvm/userland.rb
75
+ - lib/lvm/version.rb
76
+ - lib/lvm/volume_group.rb
77
+ - lib/lvm/volume_groups.rb
78
+ - lib/lvm/volumes.rb
79
+ - lib/lvm/wrapper.rb
80
+ - lib/lvm/wrapper/constants.rb
81
+ - lib/lvm/wrapper/lvs.rb
82
+ - lib/lvm/wrapper/lvsseg.rb
83
+ - lib/lvm/wrapper/pvs.rb
84
+ - lib/lvm/wrapper/pvsseg.rb
85
+ - lib/lvm/wrapper/vgs.rb
86
+ - otakumike-ruby-lvm.gemspec
87
+ - test/test_lvm.rb
88
+ homepage: https://github.com/otakumike/otakumike-ruby-lvm
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.5.1
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: A wrapper for the LVM2 administration utility, lvm. Forked for LVM 2.02.166
112
+ ONLY
113
+ test_files:
114
+ - test/test_lvm.rb