File Coverage

lib/Rex/Commands/Partition.pm
Criterion Covered Total %
statement 38 118 32.2
branch 0 40 0.0
condition 0 19 0.0
subroutine 13 16 81.2
pod 2 2 100.0
total 53 195 27.1


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             =head1 NAME
6              
7             Rex::Commands::Partition - Partition module
8              
9             =head1 DESCRIPTION
10              
11             With this Module you can partition your harddrive.
12              
13             Version <= 1.0: All these functions will not be reported.
14              
15             All these functions are not idempotent.
16              
17              
18             =head1 SYNOPSIS
19              
20             use Rex::Commands::Partition;
21              
22              
23              
24             =head1 EXPORTED FUNCTIONS
25              
26             =cut
27              
28             package Rex::Commands::Partition;
29              
30 1     1   18 use v5.12.5;
  1         3  
31 1     1   5 use warnings;
  1         2  
  1         71  
32              
33             our $VERSION = '1.14.3'; # VERSION
34              
35             require Rex::Exporter;
36 1     1   8 use base qw(Rex::Exporter);
  1         13  
  1         100  
37 1     1   15 use vars qw(@EXPORT);
  1         8  
  1         47  
38              
39 1     1   7 use Data::Dumper;
  1         1  
  1         57  
40 1     1   8 use Rex::Logger;
  1         3  
  1         8  
41 1     1   27 use Rex::Commands::Run;
  1         2  
  1         5  
42 1     1   9 use Rex::Helper::Run;
  1         3  
  1         90  
43 1     1   10 use Rex::Commands::File;
  1         3  
  1         10  
44 1     1   9 use Rex::Commands::LVM;
  1         2  
  1         7  
45 1     1   6 use Rex::Commands::Fs;
  1         2  
  1         5  
46 1     1   9 use Rex::Commands::Mkfs;
  1         5  
  1         24  
47 1     1   7 use Rex::Commands qw(TRUE FALSE);
  1         5  
  1         7  
48              
49             @EXPORT = qw(clearpart partition);
50              
51             =head2 clearpart($drive)
52              
53             Clear partitions on drive `sda`:
54              
55             clearpart "sda";
56              
57             Create a new GPT disk label (partition table) on drive `sda`:
58              
59             clearpart "sda",
60             initialize => "gpt";
61              
62             If GPT initialization is requested, the `bios_boot` option (default: TRUE) can also be set to TRUE or FALSE to control creation of a BIOS boot partition:
63              
64             clearpart "sda",
65             initialize => "gpt",
66             bios_boot => FALSE;
67              
68             =cut
69              
70             sub clearpart {
71 0     0 1   my ( $o_disk, %option ) = @_;
72              
73 0 0         $option{bios_boot} = defined $option{bios_boot} ? $option{bios_boot} : TRUE;
74 0           my $disk = _get_disk($o_disk);
75              
76 0 0         if ( $option{initialize} ) {
77              
78             # will destroy partition table
79 0           i_run "parted -s $disk mklabel " . $option{initialize}, fail_ok => 1;
80 0 0         if ( $? != 0 ) {
81 0           die("Error setting disklabel from $disk to $option{initialize}");
82             }
83              
84 0 0 0       if ( $option{initialize} eq "gpt" && $option{bios_boot} ) {
85 0           Rex::Logger::info("Creating BIOS boot partition");
86 0           partition(
87             "none",
88             fstype => "non-fs",
89             ondisk => $o_disk,
90             size => "1"
91             );
92              
93 0           i_run "parted $disk set 1 bios_grub on";
94             }
95             }
96             else {
97 0           my @partitions = grep { /\Q$o_disk\Ep?\d+$/ } split /\n/,
  0            
98             cat "/proc/partitions";
99              
100 0           for my $part_line (@partitions) {
101 0           my ( $num, $part ) = ( $part_line =~ m/\d+\s+(\d+)\s+\d+\s(.*)$/ );
102 0           Rex::Logger::info("Removing $part");
103 0           i_run "parted -s $disk rm $num";
104             }
105             }
106             }
107              
108             =head2 partition($mountpoint, %option)
109              
110             Create a partition with the specified parameters:
111              
112             =over 4
113              
114             =item ondisk
115              
116             The disk to be partitioned. Mandatory.
117              
118             =item size
119              
120             Desired size of the partition in MB. It is mandatory to pass either a C or a C parameter (but not both).
121              
122             =item grow
123              
124             If C, then the partition will take up all the available space on the disk. It is mandatory to pass either a C or a C parameter (but not both).
125              
126             =item type
127              
128             Partition type to be passed to C's C command. Optional, defaults to C.
129              
130             =item boot
131              
132             Sets boot flag on the partition if C. Optional, no boot flag is set by default.
133              
134             =item fstype
135              
136             Create a filesystem after creating the partition. Optional, no filesystem is created by default.
137              
138             =item label
139              
140             Label to be used with the filesystem. Optional, defaults to no label.
141              
142             =item mount
143              
144             If C, try to mount the partition after creating it. Optional, no mount is attempted by default.
145              
146             =item mount_persistent
147              
148             If C, try to mount the partition after creating it, and also register it in C. Optional, no mount or C manipulation is attempted by default.
149              
150             =item vg
151              
152             Creates an LVM PV, then creates the specified LVM VG (or extends it, if the VG already exists). Needs C.
153              
154             =back
155              
156             Examples:
157              
158             partition "/",
159             fstype => "ext3",
160             size => 15000,
161             ondisk => "sda",
162             type => "primary";
163              
164             partition "none",
165             type => "extended",
166             ondisk => "sda",
167             grow => 1,
168             mount => TRUE,
169              
170             partition "swap",
171             fstype => "swap",
172             type => "logical",
173             ondisk => "sda",
174             size => 8000;
175              
176             partition "/",
177             fstype => "ext3",
178             size => 10000,
179             ondisk => "sda",
180             vg => "vg0";
181              
182             =cut
183              
184             sub partition {
185 0     0 1   my ( $mountpoint, %option ) = @_;
186              
187 0   0       $option{type} ||= "primary"; # primary is default
188              
189             # info:
190             # disk size, partition start, partition end is in MB
191              
192 0 0 0       unless ( ( defined $option{grow} ) xor ( defined $option{size} ) ) {
193 0           die('You have to specify exactly one of grow or size options.');
194             }
195              
196 0 0         unless ( $option{ondisk} ) {
197 0           die("You have to specify ,,ondisk''.");
198             }
199              
200 0           my $o_disk = $option{ondisk};
201 0           my $disk = _get_disk($o_disk);
202              
203 0           my @output_lines = grep { /^\s+\d+/ } i_run "parted $disk unit kB print";
  0            
204              
205 0           my $last_partition_end = 1;
206 0           my $unit;
207 0 0         if (@output_lines) {
208 0           ($last_partition_end) = $output_lines[-1] =~ m/
209             ^\s*[\d] # partition number
210             \s+[\d\.]+kB # partition start
211             \s+([\d\.]+)kB # partition end
212             /ix;
213              
214             # convert kB to MB
215             # / 1000 because of parted, + 1 to round up
216 0           $last_partition_end =
217             sprintf( "%i", ( ( $last_partition_end / 1000 ) + 1 ) );
218             }
219              
220 0           Rex::Logger::info("Last partition ends at $last_partition_end");
221 0           my $next_partition_start = $last_partition_end;
222             my $next_partition_end =
223 0 0         $option{grow} ? "-- -1" : $last_partition_end + $option{size};
224              
225 0           i_run
226             "parted -s $disk mkpart $option{type} $next_partition_start $next_partition_end",
227             fail_ok => 1;
228              
229 0 0         if ( $? != 0 ) {
230 0           die("Error creating partition.");
231             }
232              
233 0           my $partprobe_error;
234              
235 0           for ( 1 .. 5 ) {
236 0           i_run "partprobe", fail_ok => 1;
237 0           $partprobe_error = $?;
238 0 0         last unless $partprobe_error;
239 0           sleep 5;
240             }
241              
242 0 0         die $partprobe_error if $partprobe_error;
243              
244             # get the partition id
245 0           my @partitions = grep { /\Q$o_disk\Ep?\d+$/ } split /\n/,
  0            
246             cat "/proc/partitions";
247 0           my ( $part_prefix, $part_num ) =
248             ( $partitions[-1] =~ m/\Q$o_disk\E(p)?(\d+)/ );
249 0   0       $part_prefix ||= "";
250              
251 0 0         if ( !$part_num ) {
252 0           die("Error getting partition number.");
253             }
254              
255 0 0         if ( $option{boot} ) {
256 0           i_run "parted $disk set $part_num boot on";
257             }
258              
259 0 0         if ( $option{vg} ) {
260 0           i_run "parted $disk set $part_num lvm on";
261 0           pvcreate "$disk$part_prefix$part_num";
262 0           my @vgs = vgs();
263 0 0         if ( grep { $_->{volume_group} eq $option{vg} } @vgs ) {
  0            
264              
265             # vg exists, so extend it
266 0           vgextend $option{vg}, "$disk$part_prefix$part_num";
267             }
268             else {
269             # vg doesnt exist, create a new one
270 0           vgcreate $option{vg} => "$disk$part_prefix$part_num";
271             }
272             }
273              
274 0           my $found_part = 0;
275 0           while ( $found_part == 0 ) {
276 0           Rex::Logger::debug("Waiting for $disk$part_prefix$part_num to appear...");
277              
278 0           i_run "ls -l $disk$part_prefix$part_num", fail_ok => 1;
279 0 0         if ( $? == 0 ) { $found_part = 1; last; }
  0            
  0            
280              
281 0           sleep 1;
282             }
283              
284             # don't format partition if part of a vg
285 0 0         if ( !$option{vg} ) {
286             mkfs "$disk$part_prefix$part_num",
287             fstype => $option{fstype},
288 0           label => $option{label};
289             }
290              
291 0 0 0       if ( exists $option{mount} && $option{mount} ) {
292 0           mount "$disk$part_prefix$part_num", $mountpoint, fs => $option{fstype};
293             }
294              
295 0 0 0       if ( exists $option{mount_persistent} && $option{mount_persistent} ) {
296             mount "$disk$part_prefix$part_num", $mountpoint,
297             fs => $option{fstype},
298 0   0       label => $option{label} || "",
299             persistent => 1;
300             }
301              
302 0           return "$disk$part_prefix$part_num";
303             }
304              
305             sub _get_disk {
306 0     0     my ($disk) = @_;
307              
308 0 0         if ( $disk =~ m/^\// ) {
309 0           return $disk;
310             }
311              
312 0           return "/dev/$disk";
313             }
314              
315             1;