ruby-lvm 0.0.1 → 0.1.1
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.tar.gz.sig +0 -0
- data/History.txt +10 -2
- data/Manifest.txt +18 -17
- data/README.txt +22 -9
- data/Rakefile +3 -2
- data/Todo.txt +7 -8
- data/examples/create_snapshot.rb +20 -8
- data/examples/error_handling.rb +8 -2
- data/examples/show_lvm_config.rb +40 -0
- data/lib/lvm.rb +67 -24
- data/lib/lvm/external.rb +25 -30
- data/lib/lvm/logical_volume.rb +9 -0
- data/lib/lvm/logical_volume_segment.rb +5 -0
- data/lib/lvm/logical_volumes.rb +37 -0
- data/lib/lvm/physical_volume.rb +5 -0
- data/lib/lvm/physical_volume_segment.rb +5 -0
- data/lib/lvm/physical_volumes.rb +37 -0
- data/lib/lvm/userland.rb +5 -0
- data/lib/lvm/volume_group.rb +5 -0
- data/lib/lvm/volume_groups.rb +46 -0
- data/lib/lvm/volumes.rb +16 -0
- data/lib/lvm/wrapper.rb +53 -0
- data/lib/lvm/wrapper/constants.rb +11 -0
- data/lib/lvm/wrapper/lvs.rb +127 -0
- data/lib/lvm/wrapper/lvsseg.rb +59 -0
- data/lib/lvm/wrapper/pvs.rb +84 -0
- data/lib/lvm/wrapper/pvsseg.rb +57 -0
- data/lib/lvm/wrapper/vgs.rb +112 -0
- metadata +109 -90
- metadata.gz.sig +0 -0
- data/examples/show_volumes.rb +0 -26
- data/helpers/generate_field_data.rb +0 -117
- data/lib/lvm/attrib/lvs.yaml +0 -88
- data/lib/lvm/attrib/pvs.yaml +0 -46
- data/lib/lvm/attrib/vgs.yaml +0 -55
- data/lib/lvm/lv.rb +0 -19
- data/lib/lvm/lvmanager.rb +0 -95
- data/lib/lvm/lvs.rb +0 -143
- data/lib/lvm/lvseg.rb +0 -14
- data/lib/lvm/proc.rb +0 -39
- data/lib/lvm/pv.rb +0 -15
- data/lib/lvm/pvmanager.rb +0 -22
- data/lib/lvm/pvs.rb +0 -109
- data/lib/lvm/pvseg.rb +0 -14
- data/lib/lvm/vg.rb +0 -15
- data/lib/lvm/vgmanager.rb +0 -68
- data/lib/lvm/vgs.rb +0 -123
@@ -0,0 +1,37 @@
|
|
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 ||= []
|
26
|
+
pvsseg.each do |pvseg|
|
27
|
+
if pvseg.pv_uuid == pv.uuid
|
28
|
+
pv.segments << pvseg
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
return pvs.each {|p| yield p}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/lib/lvm/userland.rb
ADDED
@@ -0,0 +1,46 @@
|
|
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
|
+
|
26
|
+
vgs.each do |vg|
|
27
|
+
vg.logical_volumes ||= []
|
28
|
+
@lvs.each do |lv|
|
29
|
+
if lv.vg_uuid == vg.uuid
|
30
|
+
vg.logical_volumes << lv
|
31
|
+
end
|
32
|
+
end
|
33
|
+
vg.physical_volumes ||= []
|
34
|
+
@pvs.each do |pv|
|
35
|
+
if pv.vg_uuid == vg.uuid
|
36
|
+
vg.physical_volumes << pv
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return vgs.each {|v| yield v}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
data/lib/lvm/volumes.rb
ADDED
data/lib/lvm/wrapper.rb
ADDED
@@ -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
|
@@ -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
|
+
|