From 3fa0b80c22d2dcba42fba37f0c1f28444ca252b7 Mon Sep 17 00:00:00 2001 From: Mo Morsi Date: Thu, 8 Aug 2013 14:32:23 -0400 Subject: [PATCH 1/2] implement disk.size and disk.clear --- lib/linux_admin/disk.rb | 34 +++++++++++++++++++++++ lib/linux_admin/distro.rb | 4 ++- spec/disk_spec.rb | 58 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/lib/linux_admin/disk.rb b/lib/linux_admin/disk.rb index 69376cb..d70750b 100644 --- a/lib/linux_admin/disk.rb +++ b/lib/linux_admin/disk.rb @@ -19,6 +19,29 @@ def initialize(args = {}) @path = args[:path] end + def size + @size ||= begin + size = nil + out = run(cmd(:fdisk), + :return_output => true, + :params => {"-l" => nil}) + out.each_line { |l| + if l =~ /Disk #{path}: ([0-9\.]*) ([KMG])B.*/ + size = case $2 + when 'K' then + $1.to_f.kilobytes + when 'M' then + $1.to_f.megabytes + when 'G' then + $1.to_f.gigabytes + end + break + end + } + size + end + end + def partitions @partitions ||= begin partitions = [] @@ -88,5 +111,16 @@ def create_partition(partition_type, size) partitions << partition partition end + + def clear! + @partitions = [] + + # clear partition table + run(cmd(:dd), + :params => { 'if=' => '/dev/zero', 'of=' => @path, + 'bs=' => 512, 'count=' => 1}) + + self + end end end diff --git a/lib/linux_admin/distro.rb b/lib/linux_admin/distro.rb index 5fc5409..0659b4d 100644 --- a/lib/linux_admin/distro.rb +++ b/lib/linux_admin/distro.rb @@ -64,7 +64,9 @@ class RedHat < Distro :mount => '/bin/mount', :umount => '/bin/umount', :shutdown => '/sbin/shutdown', - :mke2fs => '/sbin/mke2fs'} + :mke2fs => '/sbin/mke2fs', + :fdisk => '/sbin/fdisk', + :dd => '/bin/dd'} def initialize @id = :redhat diff --git a/spec/disk_spec.rb b/spec/disk_spec.rb index 4d9ea06..0ee22a8 100644 --- a/spec/disk_spec.rb +++ b/spec/disk_spec.rb @@ -12,6 +12,38 @@ end end + describe "#size" do + it "uses fdisk" do + disk = LinuxAdmin::Disk.new :path => '/dev/hda' + disk.should_receive(:run). + with(disk.cmd(:fdisk), + :return_output => true, + :params => {"-l" => nil}). + and_return("") + disk.size + end + + it "returns disk size" do + fdisk = < '/dev/hda' + disk.stub(:run).and_return(fdisk) + disk.size.should == 500.1.gigabytes + end + end + describe "#partitions" do it "uses parted" do disk = LinuxAdmin::Disk.new :path => '/dev/hda' @@ -111,4 +143,30 @@ }.should change{@disk.partitions.size}.by(1) end end + + describe "#clear!" do + it "clears partitions" do + disk = LinuxAdmin::Disk.new :path => '/dev/hda' + disk.stub(:run).and_return("") # stub out call to cmds + disk.partitions << LinuxAdmin::Partition.new + disk.clear! + disk.partitions.should be_empty + end + + it "uses dd to clear partition table" do + disk = LinuxAdmin::Disk.new :path => '/dev/hda' + disk.should_receive(:run). + with(disk.cmd(:dd), + :params => {'if=' => '/dev/zero', 'of=' => '/dev/hda', + 'bs=' => 512, 'count=' => 1}) + disk.clear! + end + + it "returns self" do + disk = LinuxAdmin::Disk.new :path => '/dev/hda' + disk.stub(:run) # stub out call to dd + disk.clear!.should == disk + end + end + end From 1f3e1781d7d86e14d05979188f2a7e24a29ea366 Mon Sep 17 00:00:00 2001 From: Mo Morsi Date: Mon, 12 Aug 2013 10:19:21 -0400 Subject: [PATCH 2/2] flush out lvm write support --- lib/linux_admin/distro.rb | 10 +++- lib/linux_admin/logical_volume.rb | 17 ++++++ lib/linux_admin/physical_volume.rb | 19 +++++++ lib/linux_admin/volume_group.rb | 23 ++++++++ spec/logical_volume_spec.rb | 70 ++++++++++++++++++++---- spec/physical_volume_spec.rb | 73 +++++++++++++++++++++---- spec/volume_group_spec.rb | 86 +++++++++++++++++++++++++++--- 7 files changed, 268 insertions(+), 30 deletions(-) diff --git a/lib/linux_admin/distro.rb b/lib/linux_admin/distro.rb index 0659b4d..87b1e9b 100644 --- a/lib/linux_admin/distro.rb +++ b/lib/linux_admin/distro.rb @@ -66,7 +66,15 @@ class RedHat < Distro :shutdown => '/sbin/shutdown', :mke2fs => '/sbin/mke2fs', :fdisk => '/sbin/fdisk', - :dd => '/bin/dd'} + :dd => '/bin/dd', + :vgdisplay => '/sbin/vgdisplay', + :pvdisplay => '/sbin/pvdisplay', + :lvdisplay => '/sbin/lvdisplay', + :lvextend => '/sbin/lvextend', + :vgextend => '/sbin/vgextend', + :lvcreate => '/sbin/lvcreate', + :pvcreate => '/sbin/pvcreate', + :vgcreate => '/sbin/vgcreate'} def initialize @id = :redhat diff --git a/lib/linux_admin/logical_volume.rb b/lib/linux_admin/logical_volume.rb index 0fd76e0..ae009cd 100644 --- a/lib/linux_admin/logical_volume.rb +++ b/lib/linux_admin/logical_volume.rb @@ -32,6 +32,23 @@ def initialize(args = {}) @sectors = args[:sectors] end + def extend_with(vg) + run(cmd(:lvextend), + :params => [self.name, vg.name]) + self + end + + def self.create(name, vg, size) + self.scan # initialize local logical volumes + run(cmd(:lvcreate), + :params => { '-n' => name, nil => vg.name, '-L' => size}) + lv = LogicalVolume.new :name => name, + :volume_group => vg, + :sectors => size + @lvs << lv + lv + end + def self.scan @lvs ||= begin vgs = VolumeGroup.scan diff --git a/lib/linux_admin/physical_volume.rb b/lib/linux_admin/physical_volume.rb index 5dc5369..b919371 100644 --- a/lib/linux_admin/physical_volume.rb +++ b/lib/linux_admin/physical_volume.rb @@ -30,6 +30,25 @@ def initialize(args = {}) @size = args[:size] end + def attach_to(vg) + run(cmd(:vgextend), + :params => [vg.name, @device_name]) + self.volume_group = vg + self + end + + # specify disk or partition instance to create physical volume on + def self.create(device) + self.scan # initialize local physical volumes + run(cmd(:pvcreate), + :params => { nil => device.path}) + pv = PhysicalVolume.new(:device_name => device.path, + :volume_group => nil, + :size => device.size) + @pvs << pv + pv + end + def self.scan @pvs ||= begin vgs = VolumeGroup.scan diff --git a/lib/linux_admin/volume_group.rb b/lib/linux_admin/volume_group.rb index 48391c8..ba838a6 100644 --- a/lib/linux_admin/volume_group.rb +++ b/lib/linux_admin/volume_group.rb @@ -30,6 +30,29 @@ def initialize(args = {}) @name = args[:name] end + def attach_to(lv) + run(cmd(:lvextend), + :params => [lv.name, self.name]) + self + end + + def extend_with(pv) + run(cmd(:vgextend), + :params => [@name, pv.device_name]) + pv.volume_group = self + self + end + + def self.create(name, pv) + self.scan # initialize local volume groups + run(cmd(:vgcreate), + :params => [name, pv.device_name]) + vg = VolumeGroup.new :name => name + pv.volume_group = vg + @vgs << vg + vg + end + def self.scan @vgs ||= begin vgs = [] diff --git a/spec/logical_volume_spec.rb b/spec/logical_volume_spec.rb index ceb8e0f..2eaec19 100644 --- a/spec/logical_volume_spec.rb +++ b/spec/logical_volume_spec.rb @@ -2,8 +2,7 @@ describe LinuxAdmin::LogicalVolume do before(:each) do - LinuxAdmin::Distro.stub(:local). - and_return(LinuxAdmin::Distros::Test.new) + LinuxAdmin::Distro.stub(:local => LinuxAdmin::Distros::Test.new) @logical_volumes = < 'lv' + vg = LinuxAdmin::VolumeGroup.new :name => 'vg' + lv.should_receive(:run). + with(vg.cmd(:lvextend), + :params => ['lv', 'vg']) + lv.extend_with(vg) + end + + it "returns self" do + lv = described_class.new :name => 'lv' + vg = LinuxAdmin::VolumeGroup.new :name => 'vg' + lv.stub(:run) + lv.extend_with(vg).should == lv + end + end + + describe "#create" do + before(:each) do + @vg = LinuxAdmin::VolumeGroup.new :name => 'vg' + end + + it "uses lvcreate" do + described_class.instance_variable_set(:@lvs, []) + described_class.should_receive(:run). + with(LinuxAdmin.cmd(:lvcreate), + :params => { '-n' => 'lv', + nil => 'vg', + '-L' => '256G' }) + described_class.create 'lv', @vg, '256G' + end + + it "returns new logical volume" do + LinuxAdmin::VolumeGroup.stub(:run => "") + described_class.stub(:run => "") + lv = described_class.create 'lv', @vg, '256G' + lv.should be_an_instance_of(described_class) + lv.name.should == 'lv' + end + + it "adds logical volume to local registry" do + LinuxAdmin::VolumeGroup.stub(:run => "") + described_class.stub(:run => "") + lv = described_class.create 'lv', @vg, '256G' + described_class.scan.should include(lv) + end + end + describe "#scan" do it "uses lvdisplay" do - LinuxAdmin::LogicalVolume.should_receive(:run). + described_class.should_receive(:run). with(LinuxAdmin.cmd(:lvdisplay), :return_output => true, :params => { '-c' => nil}). and_return(@logical_volumes) LinuxAdmin::VolumeGroup.should_receive(:run).and_return(@groups) # stub out call to vgdisplay - LinuxAdmin::LogicalVolume.scan + described_class.scan end it "returns local logical volumes" do - LinuxAdmin::LogicalVolume.should_receive(:run).and_return(@logical_volumes) + described_class.should_receive(:run).and_return(@logical_volumes) LinuxAdmin::VolumeGroup.should_receive(:run).and_return(@groups) - lvs = LinuxAdmin::LogicalVolume.scan + lvs = described_class.scan - lvs[0].should be_an_instance_of(LinuxAdmin::LogicalVolume) + lvs[0].should be_an_instance_of(described_class) lvs[0].name.should == '/dev/vg_foobar/lv_swap' lvs[0].sectors.should == 4128768 - lvs[1].should be_an_instance_of(LinuxAdmin::LogicalVolume) + lvs[1].should be_an_instance_of(described_class) lvs[1].name.should == '/dev/vg_foobar/lv_root' lvs[1].sectors.should == 19988480 end it "resolves volume group references" do - LinuxAdmin::LogicalVolume.should_receive(:run).and_return(@logical_volumes) + described_class.should_receive(:run).and_return(@logical_volumes) LinuxAdmin::VolumeGroup.should_receive(:run).and_return(@groups) - lvs = LinuxAdmin::LogicalVolume.scan + lvs = described_class.scan lvs[0].volume_group.should be_an_instance_of(LinuxAdmin::VolumeGroup) lvs[0].volume_group.name.should == 'vg_foobar' lvs[1].volume_group.should be_an_instance_of(LinuxAdmin::VolumeGroup) diff --git a/spec/physical_volume_spec.rb b/spec/physical_volume_spec.rb index 05d6bab..27ad66f 100644 --- a/spec/physical_volume_spec.rb +++ b/spec/physical_volume_spec.rb @@ -2,8 +2,7 @@ describe LinuxAdmin::PhysicalVolume do before(:each) do - LinuxAdmin::Distro.stub(:local). - and_return(LinuxAdmin::Distros::Test.new) + LinuxAdmin::Distro.stub(:local => LinuxAdmin::Distros::Test.new) @physical_volumes = < 'vg' + pv = described_class.new :device_name => '/dev/hda' + pv.should_receive(:run). + with(pv.cmd(:vgextend), + :params => ['vg', '/dev/hda']) + pv.attach_to(vg) + end + + it "assigns volume group to physical volume" do + vg = LinuxAdmin::VolumeGroup.new :name => 'vg' + pv = described_class.new :device_name => '/dev/hda' + pv.stub(:run) + pv.attach_to(vg) + pv.volume_group.should == vg + end + + it "returns self" do + vg = LinuxAdmin::VolumeGroup.new :name => 'vg' + pv = described_class.new :device_name => '/dev/hda' + pv.stub(:run) + pv.attach_to(vg).should == pv + end + end + + describe "#create" do + it "uses pvcreate" do + disk = LinuxAdmin::Disk.new :path => '/dev/hda' + described_class.instance_variable_set(:@pvs, []) + described_class.should_receive(:run). + with(LinuxAdmin.cmd(:pvcreate), + :params => { nil => '/dev/hda'}) + described_class.create disk + end + + it "returns new physical volume" do + disk = LinuxAdmin::Disk.new :path => '/dev/hda' + LinuxAdmin::VolumeGroup.stub(:run => "") + described_class.stub(:run => "") + pv = described_class.create disk + pv.should be_an_instance_of(described_class) + pv.device_name.should == '/dev/hda' + end + + it "adds physical volume to local registry" do + disk = LinuxAdmin::Disk.new :path => '/dev/hda' + LinuxAdmin::VolumeGroup.stub(:run => "") + described_class.stub(:run => "") + pv = described_class.create disk + described_class.scan.should include(pv) + end + end + describe "#scan" do it "uses pvdisplay" do - LinuxAdmin::PhysicalVolume.should_receive(:run). + described_class.should_receive(:run). with(LinuxAdmin.cmd(:pvdisplay), :return_output => true, :params => { '-c' => nil}). and_return(@physical_volumes) LinuxAdmin::VolumeGroup.should_receive(:run).and_return(@groups) # stub out call to vgdisplay - LinuxAdmin::PhysicalVolume.scan + described_class.scan end it "returns local physical volumes" do - LinuxAdmin::PhysicalVolume.should_receive(:run).and_return(@physical_volumes) + described_class.should_receive(:run).and_return(@physical_volumes) LinuxAdmin::VolumeGroup.should_receive(:run).and_return(@groups) - pvs = LinuxAdmin::PhysicalVolume.scan + pvs = described_class.scan - pvs[0].should be_an_instance_of(LinuxAdmin::PhysicalVolume) + pvs[0].should be_an_instance_of(described_class) pvs[0].device_name.should == '/dev/vda2' pvs[0].size.should == 24139776 end it "resolves volume group references" do - LinuxAdmin::PhysicalVolume.should_receive(:run).and_return(@physical_volumes) + described_class.should_receive(:run).and_return(@physical_volumes) LinuxAdmin::VolumeGroup.should_receive(:run).and_return(@groups) - pvs = LinuxAdmin::PhysicalVolume.scan + pvs = described_class.scan pvs[0].volume_group.should be_an_instance_of(LinuxAdmin::VolumeGroup) pvs[0].volume_group.name.should == 'vg_foobar' end diff --git a/spec/volume_group_spec.rb b/spec/volume_group_spec.rb index dce8f06..619d56d 100644 --- a/spec/volume_group_spec.rb +++ b/spec/volume_group_spec.rb @@ -2,8 +2,7 @@ describe LinuxAdmin::VolumeGroup do before(:each) do - LinuxAdmin::Distro.stub(:local). - and_return(LinuxAdmin::Distros::Test.new) + LinuxAdmin::Distro.stub(:local => LinuxAdmin::Distros::Test.new) @groups = < 'lv' + vg = described_class.new :name => 'vg' + vg.should_receive(:run). + with(vg.cmd(:lvextend), + :params => ['lv', 'vg']) + vg.attach_to(lv) + end + + it "returns self" do + lv = LinuxAdmin::LogicalVolume.new :name => 'lv' + vg = described_class.new :name => 'vg' + vg.stub(:run) + vg.attach_to(lv).should == vg + end + end + + describe "#extend_with" do + it "uses vgextend" do + vg = described_class.new :name => 'vg' + pv = LinuxAdmin::PhysicalVolume.new :device_name => '/dev/hda' + vg.should_receive(:run). + with(vg.cmd(:vgextend), + :params => ['vg', '/dev/hda']) + vg.extend_with(pv) + end + + it "assigns volume group to physical volume" do + vg = described_class.new :name => 'vg' + pv = LinuxAdmin::PhysicalVolume.new :device_name => '/dev/hda' + vg.stub(:run) + vg.extend_with(pv) + pv.volume_group.should == vg + end + + it "returns self" do + vg = described_class.new :name => 'vg' + pv = LinuxAdmin::PhysicalVolume.new :device_name => '/dev/hda' + vg.stub(:run) + vg.extend_with(pv).should == vg + end + end + + describe "#create" do + before(:each) do + @pv = LinuxAdmin::PhysicalVolume.new :device_name => '/dev/hda' + end + + it "uses vgcreate" do + described_class.instance_variable_set(:@vgs, []) + described_class.should_receive(:run). + with(LinuxAdmin.cmd(:vgcreate), + :params => ['vg', '/dev/hda']) + described_class.create 'vg', @pv + end + + it "returns new volume group" do + described_class.stub(:run => "") + vg = described_class.create 'vg', @pv + vg.should be_an_instance_of(described_class) + vg.name.should == 'vg' + end + + it "adds volume group to local registry" do + described_class.stub(:run => "") + vg = described_class.create 'vg', @pv + described_class.scan.should include(vg) + end end describe "#scan" do it "uses vgdisplay" do - LinuxAdmin::VolumeGroup.should_receive(:run). + described_class.should_receive(:run). with(LinuxAdmin.cmd(:vgdisplay), :return_output => true, :params => { '-c' => nil}). and_return(@groups) - LinuxAdmin::VolumeGroup.scan + described_class.scan end it "returns local volume groups" do - LinuxAdmin::VolumeGroup.should_receive(:run).and_return(@groups) - vgs = LinuxAdmin::VolumeGroup.scan + described_class.should_receive(:run).and_return(@groups) + vgs = described_class.scan - vgs[0].should be_an_instance_of(LinuxAdmin::VolumeGroup) + vgs[0].should be_an_instance_of(described_class) vgs[0].name.should == 'vg_foobar' end end