ruby-lvm 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/Manifest.txt +27 -0
- data/README.txt +59 -0
- data/Rakefile +14 -0
- data/Todo.txt +10 -0
- data/examples/create_snapshot.rb +16 -0
- data/examples/error_handling.rb +9 -0
- data/examples/show_volumes.rb +26 -0
- data/helpers/generate_field_data.rb +117 -0
- data/lib/lvm/attrib/lvs.yaml +88 -0
- data/lib/lvm/attrib/pvs.yaml +46 -0
- data/lib/lvm/attrib/vgs.yaml +55 -0
- data/lib/lvm/external.rb +41 -0
- data/lib/lvm/lv.rb +19 -0
- data/lib/lvm/lvmanager.rb +95 -0
- data/lib/lvm/lvs.rb +143 -0
- data/lib/lvm/lvseg.rb +14 -0
- data/lib/lvm/proc.rb +39 -0
- data/lib/lvm/pv.rb +15 -0
- data/lib/lvm/pvmanager.rb +22 -0
- data/lib/lvm/pvs.rb +109 -0
- data/lib/lvm/pvseg.rb +14 -0
- data/lib/lvm/vg.rb +15 -0
- data/lib/lvm/vgmanager.rb +68 -0
- data/lib/lvm/vgs.rb +123 -0
- data/lib/lvm.rb +39 -0
- data/test/test_lvm.rb +0 -0
- data.tar.gz.sig +0 -0
- metadata +116 -0
- metadata.gz.sig +0 -0
data/lib/lvm/lvs.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
module LVMWrapper
|
2
|
+
class LVS
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
BASE_COMMAND = 'lvs --verbose --separator=, --noheadings --nosuffix --units=b --unbuffered --options %s'
|
6
|
+
#,vg_uuid'
|
7
|
+
ATTRIBUTES = 'attrib/lvs.yaml'
|
8
|
+
|
9
|
+
EMPTY = '-'
|
10
|
+
|
11
|
+
# lv_attr attribute handling constants
|
12
|
+
# roughly by order referenced in lib/report/report.c:292 (_lvstatus_disp)
|
13
|
+
#
|
14
|
+
VOLUME_TYPE = {
|
15
|
+
'p' => :pvmove,
|
16
|
+
'c' => :conversion,
|
17
|
+
'M' => :mirror_not_synced,
|
18
|
+
'm' => :mirror,
|
19
|
+
'i' => :mirror_image,
|
20
|
+
'I' => :mirror_image_not_synced,
|
21
|
+
'l' => :mirror_log,
|
22
|
+
'v' => :virtual,
|
23
|
+
'o' => :origin,
|
24
|
+
's' => :snapshot,
|
25
|
+
'S' => :invalid_snapshot,
|
26
|
+
# custom, empty is a standard volume
|
27
|
+
'-' => :normal
|
28
|
+
}
|
29
|
+
PERMISSIONS = {
|
30
|
+
'w' => :writeable,
|
31
|
+
'r' => :readonly,
|
32
|
+
# custom, from reading source
|
33
|
+
'-' => :locked_by_pvmove,
|
34
|
+
}
|
35
|
+
ALLOCATION_POLICY = {
|
36
|
+
'c' => :contiguous,
|
37
|
+
'l' => :cling,
|
38
|
+
'n' => :normal,
|
39
|
+
'a' => :anywhere,
|
40
|
+
'i' => :inherited,
|
41
|
+
'C' => :contiguous_locked,
|
42
|
+
'L' => :cling_locked,
|
43
|
+
'N' => :normal_locked,
|
44
|
+
'A' => :anywhere_locked,
|
45
|
+
'I' => :inherited_locked
|
46
|
+
}
|
47
|
+
FIXED_MINOR = {
|
48
|
+
# code says its a boolean
|
49
|
+
'm' => true
|
50
|
+
}
|
51
|
+
STATE = {
|
52
|
+
's' => :suspended,
|
53
|
+
'a' => :active,
|
54
|
+
'i' => :inactive_with_table,
|
55
|
+
'd' => :inactive_without_table,
|
56
|
+
'S' => :suspended_snapshot,
|
57
|
+
'I' => :invalid_snapshot
|
58
|
+
}
|
59
|
+
DEVICE_OPEN = {
|
60
|
+
# code says its a boolean
|
61
|
+
'o' => true
|
62
|
+
}
|
63
|
+
|
64
|
+
def self.command
|
65
|
+
opts = []
|
66
|
+
attributes = YAML.load_file(File.dirname(__FILE__) + '/' + ATTRIBUTES)
|
67
|
+
attributes.each do |a|
|
68
|
+
opts << a[:option]
|
69
|
+
end
|
70
|
+
|
71
|
+
BASE_COMMAND % opts.join(",")
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.parse_lv_attr(lv_attr)
|
75
|
+
ret = {}
|
76
|
+
# translate them into nice symbols and a couple booleans
|
77
|
+
ret[:volume_type] = VOLUME_TYPE[lv_attr[0].chr]
|
78
|
+
ret[:permissions] = PERMISSIONS[lv_attr[1].chr]
|
79
|
+
ret[:allocation_policy] = ALLOCATION_POLICY[lv_attr[2].chr]
|
80
|
+
ret[:fixed_minor] = FIXED_MINOR[lv_attr[3].chr] ? true : false
|
81
|
+
ret[:state] = STATE[lv_attr[4].chr]
|
82
|
+
ret[:device_open] = DEVICE_OPEN[lv_attr[5].chr] ? true : false
|
83
|
+
ret
|
84
|
+
end
|
85
|
+
|
86
|
+
# Parses the output of self.command
|
87
|
+
def self.parse(output)
|
88
|
+
volumes = []
|
89
|
+
|
90
|
+
# lvs columns will become lv attributes
|
91
|
+
attributes = YAML.load_file(File.dirname(__FILE__) + '/' + ATTRIBUTES)
|
92
|
+
|
93
|
+
output.split("\n").each do |line|
|
94
|
+
line.strip!
|
95
|
+
# each line of output is comma separated values
|
96
|
+
values = line.split(",")
|
97
|
+
# empty values to nil
|
98
|
+
values.map! do |value|
|
99
|
+
if value.empty?
|
100
|
+
nil
|
101
|
+
else
|
102
|
+
value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
args = {}
|
107
|
+
# match up attribute => value
|
108
|
+
values.size.times do |i|
|
109
|
+
method = attributes[i][:method].to_sym
|
110
|
+
value = values[i]
|
111
|
+
# use our hints first for type conversion
|
112
|
+
if attributes[i][:type_hint] == "Integer"
|
113
|
+
value = value.to_i
|
114
|
+
elsif attributes[i][:type_hint] == "Float"
|
115
|
+
value = value.to_f
|
116
|
+
end
|
117
|
+
args[method] = value
|
118
|
+
end
|
119
|
+
|
120
|
+
# LVSEG
|
121
|
+
|
122
|
+
# now we force some types to ints since we've requested them as bytes
|
123
|
+
# without a suffix
|
124
|
+
args[:size] = args[:size].to_i
|
125
|
+
|
126
|
+
# we resolve the attributes line to nicer symbols
|
127
|
+
args.merge!(parse_lv_attr(args[:attr]))
|
128
|
+
|
129
|
+
# finally build our object
|
130
|
+
volume = LogicalVolume.new(args)
|
131
|
+
|
132
|
+
if block_given?
|
133
|
+
yield volume
|
134
|
+
else
|
135
|
+
volumes << volume
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
volumes
|
140
|
+
end # parse
|
141
|
+
|
142
|
+
end # class
|
143
|
+
end # module
|
data/lib/lvm/lvseg.rb
ADDED
data/lib/lvm/proc.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module LVMWrapper
|
2
|
+
class External
|
3
|
+
class ExternalFailure < RuntimeError; end
|
4
|
+
|
5
|
+
# Class Methods
|
6
|
+
#
|
7
|
+
class<<self
|
8
|
+
# Return output of external command
|
9
|
+
# Yield each line or return entire output
|
10
|
+
#
|
11
|
+
def cmd(cmd)
|
12
|
+
output = []
|
13
|
+
IO.popen(cmd, "r") do |p|
|
14
|
+
while line = p.gets
|
15
|
+
if defined? yield
|
16
|
+
yield line
|
17
|
+
else
|
18
|
+
output << line
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
stat = $?
|
23
|
+
if stat.exited?
|
24
|
+
if stat.exitstatus > 0
|
25
|
+
raise ExternalFailure, "Fatal error, `#{cmd}` returned #{stat.exitstatus}"
|
26
|
+
end
|
27
|
+
elsif stat.signaled?
|
28
|
+
raise ExternalFailure, "Fatal error, `#{cmd}` got signal #{stat.termsig} and terminated"
|
29
|
+
elsif stat.stopped?
|
30
|
+
raise ExternalFailure, "Fatal error, `#{cmd}` got signal #{stat.stopsig} and is stopped"
|
31
|
+
end
|
32
|
+
output.join
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Instance Methods
|
37
|
+
#
|
38
|
+
end # class
|
39
|
+
end # module
|
data/lib/lvm/pv.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module LVMWrapper
|
2
|
+
class PhysicalVolume
|
3
|
+
def initialize(args)
|
4
|
+
@attributes = args
|
5
|
+
|
6
|
+
# so many attributes.. we let the caller define them :)
|
7
|
+
meta = class << self; self; end
|
8
|
+
args.each_key do |name|
|
9
|
+
meta.send(:define_method, name) { @attributes[name] }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# helper methods
|
14
|
+
end # class
|
15
|
+
end # module
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'lvm/pv'
|
2
|
+
require 'lvm/pvs'
|
3
|
+
require 'lvm/pvseg'
|
4
|
+
|
5
|
+
module LVMWrapper
|
6
|
+
class PhysicalVolumeManager
|
7
|
+
|
8
|
+
def initialize(lvm)
|
9
|
+
@lvm = lvm
|
10
|
+
end
|
11
|
+
|
12
|
+
def create(args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def list
|
16
|
+
data = @lvm.cmd(PVS.command)
|
17
|
+
PVS.parse(data)
|
18
|
+
end
|
19
|
+
alias pvs list
|
20
|
+
|
21
|
+
end # class
|
22
|
+
end # module
|
data/lib/lvm/pvs.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
module LVMWrapper
|
2
|
+
class PVS
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
BASE_COMMAND = 'pvs --verbose --separator=, --noheadings --nosuffix --units=b --unbuffered --options %s'
|
6
|
+
ATTRIBUTES = 'attrib/pvs.yaml'
|
7
|
+
|
8
|
+
EMPTY = '-'
|
9
|
+
|
10
|
+
# pv_attr attribute handling constants
|
11
|
+
# roughly by order referenced in lib/report/report.c:360 (_pvstatus_disp)
|
12
|
+
#
|
13
|
+
ALLOCATABLE = {
|
14
|
+
# code says its a boolean
|
15
|
+
'a' => true
|
16
|
+
}
|
17
|
+
EXPORTED = {
|
18
|
+
# code says its a boolean
|
19
|
+
'x' => true
|
20
|
+
}
|
21
|
+
|
22
|
+
def self.command
|
23
|
+
opts = []
|
24
|
+
attributes = YAML.load_file(File.dirname(__FILE__) + '/' + ATTRIBUTES)
|
25
|
+
attributes.each do |a|
|
26
|
+
opts << a[:option]
|
27
|
+
end
|
28
|
+
|
29
|
+
BASE_COMMAND % opts.join(",")
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.parse_pv_attr(pv_attr)
|
33
|
+
ret = {}
|
34
|
+
# translate them into nice symbols and a couple booleans
|
35
|
+
ret[:allocatable] = ALLOCATABLE[pv_attr[0].chr] ? true : false
|
36
|
+
ret[:exported] = EXPORTED[pv_attr[1].chr] ? true : false
|
37
|
+
ret
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parses the output of self.command
|
41
|
+
def self.parse(output)
|
42
|
+
volumes = []
|
43
|
+
segs = []
|
44
|
+
|
45
|
+
# lvs columns will become lv attributes
|
46
|
+
attributes = YAML.load_file(File.dirname(__FILE__) + '/' + ATTRIBUTES)
|
47
|
+
|
48
|
+
output.split("\n").each do |line|
|
49
|
+
line.strip!
|
50
|
+
# each line of output is comma separated values
|
51
|
+
values = line.split(",")
|
52
|
+
# empty values to nil
|
53
|
+
values.map! do |value|
|
54
|
+
if value.empty?
|
55
|
+
nil
|
56
|
+
else
|
57
|
+
value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
args = {}
|
62
|
+
# match up attribute => value
|
63
|
+
values.size.times do |i|
|
64
|
+
method = attributes[i][:method].to_sym
|
65
|
+
value = values[i]
|
66
|
+
# use our hints first for type conversion
|
67
|
+
if attributes[i][:type_hint] == "Integer"
|
68
|
+
value = value.to_i
|
69
|
+
elsif attributes[i][:type_hint] == "Float"
|
70
|
+
value = value.to_f
|
71
|
+
end
|
72
|
+
args[method] = value
|
73
|
+
end
|
74
|
+
|
75
|
+
# pvs produces duplicate lines while elaborating on the segments being
|
76
|
+
# used, collect the segment data
|
77
|
+
segs << PhysicalVolumeSegment.new(:start => args[:pvseg_start], :size => args[:pvseg_size])
|
78
|
+
if args[:pvseg_start] == args[:pe_alloc_count]
|
79
|
+
args[:segments] = segs.dup
|
80
|
+
# already have em
|
81
|
+
args.delete(:pvseg_start)
|
82
|
+
args.delete(:pvseg_size)
|
83
|
+
segs.clear
|
84
|
+
else
|
85
|
+
next
|
86
|
+
end
|
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_pv_attr(args[:attr]))
|
94
|
+
|
95
|
+
# finally build our object
|
96
|
+
volume = PhysicalVolume.new(args)
|
97
|
+
|
98
|
+
if block_given?
|
99
|
+
yield volume
|
100
|
+
else
|
101
|
+
volumes << volume
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
volumes
|
106
|
+
end # parse
|
107
|
+
|
108
|
+
end # class
|
109
|
+
end # module
|
data/lib/lvm/pvseg.rb
ADDED
data/lib/lvm/vg.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module LVMWrapper
|
2
|
+
class VolumeGroup
|
3
|
+
def initialize(args)
|
4
|
+
@attributes = args
|
5
|
+
|
6
|
+
# so many attributes.. we let the caller define them :)
|
7
|
+
meta = class << self; self; end
|
8
|
+
args.each_key do |name|
|
9
|
+
meta.send(:define_method, name) { @attributes[name] }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# helper methods
|
14
|
+
end # class
|
15
|
+
end # module
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'lvm/vg'
|
2
|
+
require 'lvm/vgs'
|
3
|
+
|
4
|
+
module LVMWrapper
|
5
|
+
class VolumeGroupManager
|
6
|
+
|
7
|
+
def initialize(lvm)
|
8
|
+
@lvm = lvm
|
9
|
+
end
|
10
|
+
|
11
|
+
# vgcfgbackup Backup volume group configuration(s)
|
12
|
+
# vgcfgrestore Restore volume group configuration
|
13
|
+
# vgchange Change volume group attributes
|
14
|
+
# vgck Check the consistency of volume group(s)
|
15
|
+
# vgconvert Change volume group metadata format
|
16
|
+
# vgcreate Create a volume group
|
17
|
+
# vgdisplay Display volume group information
|
18
|
+
# vgexport Unregister volume group(s) from the system
|
19
|
+
# vgextend Add physical volumes to a volume group
|
20
|
+
# vgimport Register exported volume group with system
|
21
|
+
# vgmerge Merge volume groups
|
22
|
+
# vgmknodes Create the special files for volume group devices in /dev
|
23
|
+
# vgreduce Remove physical volume(s) from a volume group
|
24
|
+
# vgremove Remove volume group(s)
|
25
|
+
# vgrename Rename a volume group
|
26
|
+
# vgs Display information about volume groups
|
27
|
+
# vgscan Search for all volume groups
|
28
|
+
# vgsplit Move physical volumes into a new volume group
|
29
|
+
|
30
|
+
def create(args)
|
31
|
+
end
|
32
|
+
|
33
|
+
def change(args)
|
34
|
+
vgname = args[:vgname] || nil
|
35
|
+
|
36
|
+
raise ArgumentError if vgname.nil?
|
37
|
+
|
38
|
+
args.delete(:vgname)
|
39
|
+
|
40
|
+
@lvm.cmd("vgchange #{args_to_long_opts(args)} #{vgname}")
|
41
|
+
end
|
42
|
+
|
43
|
+
# ruby hash of key values to long options
|
44
|
+
def args_to_long_opts(args)
|
45
|
+
opts = []
|
46
|
+
args.each do |key,value|
|
47
|
+
opts << "--#{key.to_s} #{value}"
|
48
|
+
end
|
49
|
+
opts.join(" ")
|
50
|
+
end
|
51
|
+
|
52
|
+
def lookup(vgname)
|
53
|
+
raw_data = @lvm.cmd("#{VGS.command} #{vgname}")
|
54
|
+
VGS.parse(raw_data)[0]
|
55
|
+
end
|
56
|
+
|
57
|
+
def [](vgname)
|
58
|
+
lookup(vgname)
|
59
|
+
end
|
60
|
+
|
61
|
+
def list
|
62
|
+
data = @lvm.cmd(VGS.command)
|
63
|
+
VGS.parse(data)
|
64
|
+
end
|
65
|
+
alias vgs list
|
66
|
+
|
67
|
+
end # class
|
68
|
+
end # module
|
data/lib/lvm/vgs.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
module LVMWrapper
|
2
|
+
class VGS
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
BASE_COMMAND = 'vgs --verbose --separator=, --noheadings --nosuffix --units=b --unbuffered --options %s'
|
6
|
+
ATTRIBUTES = 'attrib/vgs.yaml'
|
7
|
+
|
8
|
+
EMPTY = '-'
|
9
|
+
|
10
|
+
# vg_attr attribute handling constants
|
11
|
+
# roughly by order referenced in lib/report/report.c:360 (_vgstatus_disp)
|
12
|
+
#
|
13
|
+
PERMISSIONS = {
|
14
|
+
'w' => :writeable,
|
15
|
+
'r' => :readonly,
|
16
|
+
}
|
17
|
+
RESIZEABLE = {
|
18
|
+
# code says its a boolean
|
19
|
+
'z' => true
|
20
|
+
}
|
21
|
+
EXPORTED = {
|
22
|
+
# code says its a boolean
|
23
|
+
'x' => true
|
24
|
+
}
|
25
|
+
PARTIAL = {
|
26
|
+
# code says its a boolean
|
27
|
+
'p' => true
|
28
|
+
}
|
29
|
+
ALLOCATION_POLICY = {
|
30
|
+
'c' => :contiguous,
|
31
|
+
'l' => :cling,
|
32
|
+
'n' => :normal,
|
33
|
+
'a' => :anywhere,
|
34
|
+
'i' => :inherited,
|
35
|
+
'C' => :contiguous_locked,
|
36
|
+
'L' => :cling_locked,
|
37
|
+
'N' => :normal_locked,
|
38
|
+
'A' => :anywhere_locked,
|
39
|
+
'I' => :inherited_locked
|
40
|
+
}
|
41
|
+
CLUSTERED = {
|
42
|
+
# code says its a boolean
|
43
|
+
'c' => true
|
44
|
+
}
|
45
|
+
|
46
|
+
def self.command
|
47
|
+
opts = []
|
48
|
+
attributes = YAML.load_file(File.dirname(__FILE__) + '/' + ATTRIBUTES)
|
49
|
+
attributes.each do |a|
|
50
|
+
opts << a[:option]
|
51
|
+
end
|
52
|
+
|
53
|
+
BASE_COMMAND % opts.join(",")
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.parse_vg_attr(vg_attr)
|
57
|
+
ret = {}
|
58
|
+
# translate them into nice symbols and a couple booleans
|
59
|
+
ret[:permissions] = PERMISSIONS[vg_attr[0].chr]
|
60
|
+
ret[:resizeable] = RESIZEABLE[vg_attr[1].chr] ? true : false
|
61
|
+
ret[:exported] = EXPORTED[vg_attr[2].chr] ? true : false
|
62
|
+
ret[:partial] = PARTIAL[vg_attr[3].chr] ? true : false
|
63
|
+
ret[:allocation_policy] = ALLOCATION_POLICY[vg_attr[4].chr]
|
64
|
+
ret[:clustered] = CLUSTERED[vg_attr[5].chr] ? true : false
|
65
|
+
ret
|
66
|
+
end
|
67
|
+
|
68
|
+
# Parses the output of self.command
|
69
|
+
def self.parse(output)
|
70
|
+
volumes = []
|
71
|
+
|
72
|
+
# lvs columns will become lv attributes
|
73
|
+
attributes = YAML.load_file(File.dirname(__FILE__) + '/' + ATTRIBUTES)
|
74
|
+
|
75
|
+
output.split("\n").each do |line|
|
76
|
+
line.strip!
|
77
|
+
# each line of output is comma separated values
|
78
|
+
values = line.split(",")
|
79
|
+
# empty values to nil
|
80
|
+
values.map! do |value|
|
81
|
+
if value.empty?
|
82
|
+
nil
|
83
|
+
else
|
84
|
+
value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
args = {}
|
89
|
+
# match up attribute => value
|
90
|
+
values.size.times do |i|
|
91
|
+
method = attributes[i][:method].to_sym
|
92
|
+
value = values[i]
|
93
|
+
# use our hints first for type conversion
|
94
|
+
if attributes[i][:type_hint] == "Integer"
|
95
|
+
value = value.to_i
|
96
|
+
elsif attributes[i][:type_hint] == "Float"
|
97
|
+
value = value.to_f
|
98
|
+
end
|
99
|
+
args[method] = value
|
100
|
+
end
|
101
|
+
|
102
|
+
# now we force some types to ints since we've requested them as bytes
|
103
|
+
# without a suffix
|
104
|
+
args[:size] = args[:size].to_i
|
105
|
+
|
106
|
+
# we resolve the attributes line to nicer symbols
|
107
|
+
args.merge!(parse_vg_attr(args[:attr]))
|
108
|
+
|
109
|
+
# finally build our object
|
110
|
+
volume = VolumeGroup.new(args)
|
111
|
+
|
112
|
+
if block_given?
|
113
|
+
yield volume
|
114
|
+
else
|
115
|
+
volumes << volume
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
volumes
|
120
|
+
end # parse
|
121
|
+
|
122
|
+
end # class
|
123
|
+
end # module
|
data/lib/lvm.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'lvm/external'
|
2
|
+
|
3
|
+
module LVMWrapper
|
4
|
+
VERSION = '0.0.1'
|
5
|
+
COMPAT_VERSION = '2.02.26-RHEL5'
|
6
|
+
|
7
|
+
class LVM
|
8
|
+
class LVM < Exception; end
|
9
|
+
|
10
|
+
attr_accessor :command
|
11
|
+
|
12
|
+
DEFAULT_COMMAND = '/sbin/lvm'
|
13
|
+
|
14
|
+
def initialize(args = {})
|
15
|
+
@command = args[:command] || DEFAULT_COMMAND
|
16
|
+
@debug = args[:debug] || false
|
17
|
+
end
|
18
|
+
|
19
|
+
def raw(args) #:nodoc:
|
20
|
+
External.cmd(args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cmd(args)
|
24
|
+
to_exec = "#{@command} #{args}"
|
25
|
+
puts "Going to execute `#{to_exec}`" if @debug
|
26
|
+
raw(to_exec)
|
27
|
+
end
|
28
|
+
|
29
|
+
class<<self
|
30
|
+
def raw(args)
|
31
|
+
new(args).raw(args)
|
32
|
+
end
|
33
|
+
def cmd(args)
|
34
|
+
new(args).raw(args)
|
35
|
+
end
|
36
|
+
end # self
|
37
|
+
|
38
|
+
end # class
|
39
|
+
end # module
|
data/test/test_lvm.rb
ADDED
File without changes
|
data.tar.gz.sig
ADDED
Binary file
|