#!/bin/bash
#-------------------------------------------------------------------------------
# lvm-test.sh                               (C) 2007-2008 T.Birnthaler OSTC GmbH
# LVM (Logical Volume Management) testen.
# $Id: lvm-test.sh,v 1.12 2011/02/03 20:17:01 tsbirn Exp $
#-------------------------------------------------------------------------------
# * Übliche Dateisystem-Struktur:
#
#       /mnt/mp3     /mnt/data     /mnt/snap    Mountpunkt
#          |             |             |
#         ext2        reiserfs        ext3      Dateisystem
#          |             |             |
#      /dev/sda3     /dev/hda5     /dev/md0     Partition
#
# * LVM = Abstraktionsschicht: Statt physikalische Festplatten-(Partitionen)
#   direkt zu verwenden, diese in "Physikalische Volumes" (PV) umwandeln, dann
#   zu beliebig großer "Volume Group" (VG) zusammenfassen (auch größer als
#   existierende Hardware-Platte!) und daraus beliebig große "Logische Volumes"
#   (LV) ausschneiden (auch größer als existierende Hardware-Platte!). Diese
#   wesentlich flexibler handhabbaren LVs übernehmen die Rolle der Partitionen.
#
# * LVM-Struktur:
#
#       /mnt/mp3     /mnt/data     /mnt/snap    Mountpunkt
#          |             |             |
#         ext2        reiserfs        ext3      Dateisystem
#          |             |             |
#   #======|=============|=============|=========================#
#   X      |             |             |                         X
#   X  +-------+     +-------+     +-------+                     X
#   X  |  LV1  |     |  LV2  |     |  LV3  |    Logical Volume   X
#   X  +-------+     +-------+     +-------+                     X
#   X        \           |            /                          X
#   X      +----------------------------+                        X
#   X      |            VG0             |       Volume Group     X
#   X      +----------------------------+                        X
#   X       /       |         |       \                          X
#   X  +-----+   +-----+   +-----+   +-----+                     X
#   X  | PV1 |   | PV2 |   | PV3 |   | PV4 |    Physical Volume  X
#   X  +-----+   +-----+   +-----+   +-----+                     X
#   X     |         |         |         |                        X
#   #=====|=========|=========|=========|========================#
#         |         |         |         |
#     /dev/sda3 /dev/hda5 /dev/md0  /dev/loop1  Partition
#
# * Logische Volumes anstelle der physikalischer Partitionen verwenden,
#   d.h. mit einem Dateisystem formatieren (z.B. ext2/3, xfs, jfs, ReiserFS)
#   und dann im Dateisystem an beliebigen Mountpunkten einhängen.
#
# * Kleinste LVM-Verwaltungseinheit ist nicht Sektor/Cluster (512 Byte/4 KByte),
#   sondern "Physical Extent" (PE) a 4 MByte (meist).
#
# * Es lassen sich nachträglich "PVs" zu einer "VG" hinzufügen oder aus ihr
#   entfernen (ohne Datenverlust), sofern der restliche Platz für die darauf
#   abgelegten Daten ausreichend ist. Dabei werden im Hintergrund AUTOMATISCH
#   Daten zwischen "PVs" hin- und hergeschoben.
#
# * In einer "VG" können beliebig viele "LVs" angelegt oder wieder aus ihr
#   entfernt werden. Weiterhin können "LVs" beliebig vergrößert/verkleinert
#   werden (das darauf eingerichtete Dateisystem muss dies allerdings ebenfalls
#   erlauben und in einem getrennten Schritt NACHHER vergrößert bzw. VORHER
#   verkleinert werden).
#
# * "LV"s können nachträglich zwischen "PV"s hin- und hergeschoben bzw. auch
#   auf einem "PV" fixiert werden (pvmove).
#
# * Von einem "LV" ist ein "Snapshot" des aktuellen Standes z.B. zu Sicherungs-
#   zwecken möglich. Änderungen an den Daten dieses "LV" wirken sich nicht auf
#   den Snapshot aus, sondern werden in davon getrennten Bereichen gespeichert.
#   Der zusätzliche Plattenplatz umfasst nur die geänderten Sektoren, solange
#   der Snapshot existiert. Bei LVM(1) waren Snapshots per Default "read-only",
#   seit LVM2 sind Snapshots "read-writable" per Default.
#
# * Geringer Performance-Verlust gegenüber direktem Plattenzugriff (2-5%).
#
# * Gewinn an Flexibilität ist allerdings enorm.
#
# * Fällt eine PV einer VG aus, so sind alle LVs, die darauf Daten abgelegt
#   haben, nicht mehr funktionsfähig (eine Datensicherung und/oder RAID-Systeme
#   als Basis der PV sind also wie immer auch hier angebracht).
#
# * LVM-Verwaltungsinformationen liegen mehrfach verteilt vor. ??? wo
#
# * Begriffe:
#   + EVMS = Enterprise Volume Management System
#   + Partition (Physikalisch/Logisch/RAID/Loop)
#   + LVM = Logical Volume Management (zugehörige Befehle "lvm...")
#   + PV  = Physical Volume           (zugehörige Befehle "pv...")
#   + VG  = Volume Group              (zugehörige Befehle "vg...")
#   + LV  = Logical Volume            (zugehörige Befehle "lv...")
#
# * Konfigurations- und Verwaltungsdateien:
#     /etc/lvm/lvm.conf
#     /etc/lvm/.cache
#     /etc/lvm/metadata
#     /etc/lvm/archive
#     /etc/lvm/backup
#     /var/lock/lvm
#
# * Plattennamen:
#     /dev/VG/LV   (z.B. /dev/vg0/data)
#
# * Befehle
#
#   + Basisbefehl (alle anderen Kommandos = symb. Links auf Kommando "lvm"):
#       lvm help       = LVM-Kommandoliste
#       lvm help CMD   = LVM-Kommando "CMD" erklären
#       lvm dumpconfig = LVM-Konfiguration anzeigen (als root!)
#       lvm formats    = Mögliche Metadaten-Formate anzeigen
#       lvm segtypes   = Mögliche Segment-Typen anzeigen
#       lvm version    = Versions-Information anzeigen (Software + Treiber)
#       lvm-bin-scan   = Symb. Links von Tools in "/sbin" zu "lvm" ziehen
#       lvmchange      = With the device mapper obsolete and does nothing
#       lvmdiskscan    = List devices that may be used as physical volumes
#       lvmsadc        = Collect activity data
#       lvmsar         = Create activity report
#
#   + Physikalische Volumes "PV" verwalten:
#      ?pvchange       = Change attributes of physical volume(s)
#      *pvcreate       = Initialize physical volume(s) for use by LVM
#      -pvdata         = Display the on-disk metadata for physical volume(s)
#      *pvdisplay      = Display various attributes of physical volume(s)
#    -->pvmove         = Move extents from one physical volume to another
#      *pvremove       = Remove LVM label(s) from physical volume(s)
#    -->pvresize       = Resize physical volume(s)
#      *pvscan         = List all physical volumes
#      *pvs            = Display information about physical volumes
#
#   + Volume Groups "VG" verwalten:
#       vgcfgbackup    = Backup volume group configuration(s)
#       vgcfgrestore   = Restore volume group configuration
#      ?vgchange       = Change volume group attributes
#      *vgck           = Check the consistency of volume group(s)
#       vgconvert      = Change volume group metadata format
#      *vgcreate       = Create a volume group
#      *vgdisplay      = Display volume group information
#      ?vgexport       = Unregister volume group(s) from the system
#      *vgextend       = Add physical volumes to a volume group
#      ?vgimport       = Register exported volume group with system
#    -->vgmerge        = Merge volume groups
#       vgmknodes      = Create special files for volume group devices in /dev
#      *vgreduce       = Remove physical volume(s) from a volume group
#      *vgremove       = Remove volume group(s)
#      *vgrename       = Rename a volume group
#      *vgscan         = Search for all volume groups
#    -->vgsplit        = Move physical volumes into a new volume group
#      *vgs            = Display information about volume groups
#
#   + Logische Volumes "LV" verwalten:
#      ?lvchange       = Change the attributes of logical volume(s)
#       lvconvert      = Change logical volume layout
#      *lvcreate       = Create a logical volume
#      *lvdisplay      = Display information about a logical volume
#      *lvextend       = Add space to a logical volume
#      *lvreduce       = Reduce the size of a logical volume
#      *lvremove       = Remove logical volume(s) from the system
#      *lvrename       = Rename a logical volume
#    -->lvresize       = Resize a logical volume
#      *lvscan         = List all logical volumes in all volume groups
#      *lvs            = Display information about logical volumes
#-------------------------------------------------------------------------------
# Muss als root ausgeführt werden
[ "$UID" != 0 ] && echo "Muss root sein!" && exit 1

# Prompt für Debug-Meldungen
PS4="CMD> "
# Debug-Meldungen einschalten (-x=execute)
set -x

#-------------------------------------------------------------------------------
# LOOP-Partitionen für Test einrichten
#-------------------------------------------------------------------------------

# LOOP-Partitionen (da evtl. keine physikalischen Partition verfügbar)
P1="/dev/loop1"
P2="/dev/loop2"
P3="/dev/loop3"

# Leere Dateien für Platten-Simulation perl "Loop" anlegen
mkdir /tmp/lvm
dd if=/dev/zero of=/tmp/lvm/part1 count=10000 bs=1024
dd if=/dev/zero of=/tmp/lvm/part2 count=10000 bs=1024
dd if=/dev/zero of=/tmp/lvm/part3 count=10000 bs=1024
ls -l /tmp/lvm

# Loop-Devices schon belegt? -> Abbruch
losetup -a | grep "$P1" && echo "loop1 schon belegt" && exit
losetup -a | grep "$P2" && echo "loop2 schon belegt" && exit
losetup -a | grep "$P3" && echo "loop3 schon belegt" && exit

# Leere Dateien als Loop-Device einrichten
losetup $P1 /tmp/lvm/part1
losetup $P2 /tmp/lvm/part2
losetup $P3 /tmp/lvm/part3
losetup -a

#-------------------------------------------------------------------------------
# HIER FÄNGT LVM AN
#-------------------------------------------------------------------------------

# Alle Platten nach Physical Volumes und Volume Groups durchsuchen
# (nach HW-Änderungen sinnvoll)
vgscan

#-------------------------------------------------------------------------------
# PHYSICAL VOLUME
#-------------------------------------------------------------------------------

# Partitionen zu Physikalischen Volumes (PV) machen
pvcreate $P1
pvcreate $P2
pvcreate $P3
pvdisplay $P1
pvdisplay $P2
pvdisplay $P3

# Informationen zu Physikalischen Volumes (PV) ausgeben
pvscan
pvs

read -n 1 -p "###> Physical Volumes erzeugt, weiter? "

#-------------------------------------------------------------------------------
# VOLUME GROUP
#-------------------------------------------------------------------------------

# Volume Group (VG) "vg0" aus den beiden ersten Partitionen erzeugen
# (die dritte wird erst später hinzugefügt!)
vgcreate vg0 $P1 $P2
vgdisplay vg0
# Geht hier noch nicht !!!
#ls /dev/vg*

# Informationen zu Volume Group (VG) ausgeben
vgscan
vgs

# Volume Group (VG) überprüfen
vgck

read -n 1 -p "###> Volume Group erzeugt, weiter? "

# Volume Group (VG) umbenennen (und wieder zurückbenennen)
# (/dev/vg0 wird erst erzeugt, wenn Logical Volumes darin angelegt!)
# (/dev/vg0 kann nicht umbenannt werden, wenn Logical Volumes darin angelegt!)
vgrename vg0 vg9
vgs
vgrename /dev/vg9 /dev/vg0
vgs

read -n 1 -p "###> Volume Groups umbenannt, weiter? "

#-------------------------------------------------------------------------------
# LOGICAL VOLUME
#-------------------------------------------------------------------------------

# Zwei Logische Volumes (LV) in Gruppe "vg0" erzeugen: "data" und "mp3"
lvcreate --size 3m --name data vg0
lvcreate --size 5m --name mp3  vg0
lvdisplay /dev/vg0/data   # bzw. /dev/evms/...
lvdisplay /dev/vg0/mp3
vgdisplay vg0

# Informationen zu Logical Volume (LV) ausgeben
lvscan
lvs

read -n 1 -p "###> Logisches Volumes erzeugt, weiter? "

# Logisches Volume (LV) umbenennen (und wieder zurückbenennen)
lvrename vg0 data abcxyz
lvscan
lvs
ls /dev/vg0
lvrename /dev/vg0/abcxyz /dev/vg0/data
lvsscan
lvs
ls /dev/vg0

read -n 1 -p "###> Logisches Volume umbenannt, weiter? "

#-------------------------------------------------------------------------------
# FILE SYSTEMS
#-------------------------------------------------------------------------------

# Dateisysteme auf logischen Volumes anlegen (-m 0 = 0% für root reserviert)
mkfs -t ext2 -m 0 /dev/vg0/data   # bzw. /dev/evms/...
mkfs -t ext2 -m 0 /dev/vg0/mp3

# Mountpunkte für Einbindung der logischen Volumes anlegen
mkdir /mnt/data
mkdir /mnt/mp3
mkdir /mnt/snapshot

# Logische Volumes montieren
mount /dev/vg0/data /mnt/data
mount /dev/vg0/mp3  /mnt/mp3
ls /mnt/data
ls /mnt/mp3

# Logisches Volume "mp3" füllen
df -h
echo "1"   > /mnt/mp3/111.mp3
echo "22"  > /mnt/mp3/222.mp3
echo "333" > /mnt/mp3/333.mp3
ls /mnt/mp3

read -n 1 -p "###> Dateisystem auf LV angelegt und montiert, weiter? "

#-------------------------------------------------------------------------------
# Snapshot machen (z.B. zum Sichern)
#-------------------------------------------------------------------------------
# WICHTIG: Dieses Modul muss geladen sein für Snapshots!!!
modprobe dm-snapshot

# Snapshot "snap" von Logischem Volume "mp3" erzeugen (Größe 1 MByte)
# ACHTUNG: Namen "snapshot" NICHT verwenden!!!
# ACHTUNG: In LVM2 sind snapshots per Default auch schreibbar!!!
#lvcreate --size 1m --snapshot --name snap /dev/vg0/mp3
#lvcreate -L 1m --snapshot -n snap /dev/vg0/mp3
lvcreate -L 1m --snapshot -n snap --permission r /dev/vg0/mp3
ls /dev/vg0                                       # -> /dev/vg0/snap neu!
lvscan
lvs

# Snapshot "read-only" montieren
mount -o ro /dev/vg0/snap /mnt/snapshot/          # ro=Read-Only!
ls /mnt/snapshot

read -n 1 -p "###> Snapshot read-only montiert, weiter? "

# Logisches Volume "mp3" ändern
ls /mnt/mp3
echo "4444" > /mnt/mp3/444.mp3
ls /mnt/mp3

# Snapshot sollte unverändert sein
ls /mnt/snapshot

# Information über Snapshot-Größe und -Auslastung
lvs -o lv_name,lv_size,origin,snap_percent,lv_attr /dev/vg0/snap

# Snapshot löschen
umount /mnt/snapshot
lvremove -f /dev/vg0/snap                     # -f=force = no confirmation

# Logisches Volume "mp3" sollte unverändert sein
ls /mnt/mp3

lvs
read -n 1 -p "###> Snapshot durchgeführt, weiter? "

#-------------------------------------------------------------------------------
# Logisches Volume "mp3" vergrößern
# (REIHENFOLGE: Zuerst LV vergrößern, dann Dateisystem)
#-------------------------------------------------------------------------------
umount /mnt/mp3                # Notwendig!

# ZUERST: Logisches Volume "mp3" vergrößern
# (Geht erst mal nicht nicht, da kein Platz mehr in "vg0"!)
lvextend -L +8m /dev/vg0/mp3
#lvextend --size +8m /dev/vg0/mp3

# Drittes Physikalisches Volume zu "vg0" hinzufügen
vgdisplay vg0
vgextend vg0 $P3
vgdisplay vg0

# ZUERST: Logisches Volume "mp3" vergrößern
lvextend -L +8m /dev/vg0/mp3
#lvresize --size +8m /dev/vg0/mp3

# DANN: Dateisysteme vergrößern (fsck davor nötig!)
e2fsck -f /dev/vg0/mp3         # -force = keine Rückfrage
resize2fs /dev/vg0/mp3         # Neue Größe des Dateisystem entspricht Größe LV

# Vergrößertes Dateisystem anzeigen
mount /dev/vg0/mp3 /mnt/mp3
df -h

read -n 1 -p "###> Logisches Volume vergrößert, weiter? "

#-------------------------------------------------------------------------------
# Logisches Volume "mp3" verkleinern
# (REIHENFOLGE: Zuerst Dateisystem verkleinern, dann LV)
#-------------------------------------------------------------------------------
umount /mnt/mp3                # Notwendig!

# ZUERST: Dateisystem verkleinern (fsck davor nötig)
e2fsck -f /dev/vg0/mp3         # -force = keine Rückfrage
resize2fs /dev/vg0/mp3 8m      # Beim Verkleinern ist Zielgröße anzugeben

# DANN: Logisches Volume "mp3" verkleinern
lvreduce -f -L 8m /dev/vg0/mp3         # -force = keine Rückfrage
#lvreduce -f --size 8m /dev/vg0/mp3

# Verkleinertes Dateisystem anzeigen
mount /dev/vg0/mp3 /mnt/mp3
df -h

read -n 1 -p "###> Logisches Volume verkleinert, weiter? "

#-------------------------------------------------------------------------------
# Alles wieder aufräumen
#-------------------------------------------------------------------------------
# Alle Platten nach Physical Volumes und Volume Groups durchsuchen
# (nach HW-Änderungen sinnvoll)
vgscan -v

# Logische Volumes demontieren
umount /mnt/data
umount /mnt/mp3

# Mountpunkte löschen
rm -r /mnt/data
rm -r /mnt/mp3
rm -r /mnt/snapshot

# Logische Volumes löschen
lvs
lvremove -f /dev/vg0/data        # -force = keine Rückfrage
lvremove -f /dev/vg0/mp3         # -force = keine Rückfrage
lvs

# ALLE Physical Volumes aus Volume-Group raus
vgs
vgreduce vg0 $P1
vgreduce vg0 $P2
vgreduce vg0 $P3    # Nicht notwendig, warum?
vgs

# Volume-Group löschen (geht nur wenn alle Physical Volumes entfernt)
vgremove vg0
vgs

# Physical Volumes löschen
pvs
pvremove $P1
pvremove $P2
pvremove $P3
pvs

# Loop-Devices löschen (geht nur wenn alle Physical Volumes gelöscht)
losetup -d $P1
losetup -d $P2
losetup -d $P3

# Hilfsdateien + Hilfsverz. löschen
rm /tmp/lvm/part1
rm /tmp/lvm/part2
rm /tmp/lvm/part3
rmdir /tmp/lvm

#-------------------------------------------------------------------------------
# TODO
# * Unterschied lvresize <-> lvextend
#
# * http://lists.debian.org/debian-user-german/2003/05/msg00449.html
#   + Schritte für's Vergrößern:
#     umount /data
#     lvresize -L +10G /dev/vg0/data
#     tune2fs -O ^has_journal /dev/vg0/data
#     e2fsck -f /dev/vg0/data
#     resize2fs /dev/vg0/data
#     tune2fs -j /dev/vg0/data
#     mount /data
#
#   + Schritte für's Verkleinern:
#     umount /data
#     tune2fs -O ^has_journal /dev/vg0/data
#     e2fsck -f /dev/vg0/data
#     resize2fs /dev/vg0/data <new size>
#     tune2fs -l /dev/vg0/data | grep "^Block size"
#     #        ermittelt die Block-Größe <block size>
#     #        <new size> = <gewünschte Größe in GB> * \
#     #        1024 * 1024 * 1024 / <block size>
#     lvresize -L <new size>G /dev/vg0/data
#     tune2fs -j /dev/vg0/data
#     mount /data
#-------------------------------------------------------------------------------

