How to resize LVMs on the fly under VMware

When last we joined our intrepid hero, back in *checks notes* 2009.. I was working at a university, helping to run their internal cloud and they had a policy of setting up LVM for all the linux VMs, and I wrote the blog post so I could remember how to do online resizes.

I no longer work in that job, country, or sector, but I still use LVM on my home VMs, so still need them sometimes. However today I needed to extend an LVM containing a PV that was the entire disk, not just a partition, and the instructions didn’t work for me, so this is what I had to do..


root@serverName:~# df -h
Filesystem                 Size  Used Avail Use% Mounted on
/dev/mapper/vgRoot-lvRoot   15G  7.4G  6.6G  53% /
/dev/mapper/vgData-lvData   98G   93G     0 100% /data
#
# Firstly, we see that the volume is 100% full, so we extend in VMWare to 200GB
# and rescan partition geometry
#
root@serverName:/data# echo '1' > /sys/class/scsi_disk/32\:0\:1\:0/device/rescan 
#
# Next, run fdisk for info only, to check it's seen as a 200GB device. We don't make
# any changes though!
#
root@serverName:/data# fdisk /dev/sdb

Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

The old LVM2_member signature will be removed by a write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x44d591a2.

Command (m for help): p
Disk /dev/sdb: 200 GiB, 214748364800 bytes, 419430400 sectors
Disk model: Virtual disk    
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x44d591a2

Command (m for help): q
#
# Correct new drive size is seen, so we rescan/resize the PV
#
root@serverName:/data# pvresize /dev/sdb
  Physical volume "/dev/sdb" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
#
# Next, we extend the LV into the new space
#
root@serverName:/data# lvextend -L+100G /dev/vgData/lvData 
  Size of logical volume vgData/lvData changed from <100.00 GiB (25599 extents) to <200.00 GiB (51199 extents).
  Logical volume vgData/lvData successfully resized.
#
# Verify the new space is seen in the LV
#
root@serverName:/data# lvdisplay
  --- Logical volume ---
  LV Path                /dev/vgData/lvData
  LV Name                lvData
  VG Name                vgData
  LV UUID                WsxT1O-jzLF-D4fP-1AN5-ApQs-Kx6i-yQx2iA
  LV Write Access        read/write
  LV Creation host, time ubuntu-server, 2020-08-09 05:07:00 +0000
  LV Status              available
  # open                 1
  LV Size                <200.00 GiB
  Current LE             51199
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:0
   
  --- Logical volume ---
  LV Path                /dev/vgRoot/lvRoot
  LV Name                lvRoot
  VG Name                vgRoot
  LV UUID                9bpv9H-q53y-TwUC-n8k5-vYgi-y0ay-lBY367
  LV Write Access        read/write
  LV Creation host, time ubuntu-server, 2020-08-09 05:07:01 +0000
  LV Status              available
  # open                 1
  LV Size                <15.00 GiB
  Current LE             3839
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:1
#
# Finally resize the filesystem inside the LV
#
root@serverName:/data# resize2fs /dev/vgData/lvData 
resize2fs 1.45.5 (07-Jan-2020)
Filesystem at /dev/vgData/lvData is mounted on /data; on-line resizing required
old_desc_blocks = 13, new_desc_blocks = 25
The filesystem on /dev/vgData/lvData is now 52427776 (4k) blocks long.
#
# And we're done!
#
root@serverName:/data# df -h
Filesystem                 Size  Used Avail Use% Mounted on
/dev/mapper/vgRoot-lvRoot   15G  7.4G  6.6G  53% /
/dev/mapper/vgData-lvData  197G   93G   95G  50% /data
root@serverName:/data# 

merging passwd and shadow files

I wrote a Perl script to merge /etc/passwd and /etc/shadow files from two hosts

In the words of Elizabeth “Now you have two problems?”

See below. Sadly wordpress doesn’t do.. well.. any job of indenting. And in case you’re wondering, I’ve munged the passwd hash in the file :P

#!/usr/bin/perl
open PASSWD, "</etc/passwd" or die $!;
open OPASSWD, "<passwd.other" or die $!;
open OSHADOW, "<shadow.other" or die $!;
# Read this hosts /etc/passwd into memory
# nfsnobody:x:4294967294:4294967294:Anonymous NFS User:/var/lib/nfs:/dev/null
while ( <PASSWD> ) {
chomp;
my ($uid,$junkpass,$pruid,$pguid,$officename,$homedir,$shell) = split(/:/,$_,7);
$THISHOST{$uid}{'junkpass'} = $junkpass;
$THISHOST{$uid}{'pruid'} = $pruid;
$THISHOST{$uid}{'pguid'} = $pguid;
$THISHOST{$uid}{'officename'} = $officename;
$THISHOST{$uid}{'homedir'} = $homedir;
$THISHOST{$uid}{'shell'} = $shell;
}
close PASSWD;
# Read other machine's /etc/passwd into memory
while (<OPASSWD>) {
chomp;
my ($uid,$junkpass,$pruid,$pguid,$officename,$homedir,$shell) = split(/:/,$_,7);
$THATHOST{$uid}{'junkpass'} = $junkpass;
$THATHOST{$uid}{'pruid'} = $pruid;
$THATHOST{$uid}{'pguid'} = $pguid;
$THATHOST{$uid}{'officename'} = $officename;
$THATHOST{$uid}{'homedir'} = $homedir;
$THATHOST{$uid}{'shell'} = $shell;
}
close OPASSWD;
# Read other machine's /etc/shadow into memory
# aua:$1$6LzssYvL$Wqs94Dv/ZSkuGl0LXQpKb1:13392:0:99999:7:::
while (<OSHADOW>) {
chomp;
my ($uid,$passstring) = split(/:/,$_,2);
$THATSHADOW{$uid} = $passstring;
}
close OSHADOW;
# Check for missing accounts
foreach $account (sort keys %THATHOST) {
if (!(defined($THISHOST{$account}))) {
print "Missing $account\n";
$passwdbuf = $passwdbuf . "$account:$THATHOST{$account}{junkpass}:$THATHOST{$account}{pruid}:$THATHOST{$account}{pguid}:$THATHOST{$account}{officename}:$THATHOST{$account}{homedir}:$THATHOST{$account}{shell}\n";
$shadowbuf = $shadowbuf . "$account:$THATSHADOW{$account}\n";
} else {
print "$account: $THISHOST{$account}{pruid} = $THATHOST{$account}{pruid}\n";
}
if ((defined($THISHOST{$account})) && ($THISHOST{$account}{pruid} ne $THATHOST{$account}{pruid})) {
$uiderrors = $uiderrors . "$account : THISHOST:$THISHOST{$account}{pruid} THATHOST:$THATHOST{$account}{pruid}\n";
}
}
# Output missing accounts for /etc/passwd
print "------------------\n";
print "Add to /etc/passwd\n";
print "$passwdbuf\n";
# Output missing accounts for /etc/shadow
print "------------------\n";
print "Add to /etc/shadow\n";
print "$shadowbuf\n";
# UID Mis-matches
print "------------------\n";
print "UID Mis-matches\n";
print "$uiderrors\n";