Skip to content

LVM

LVM2 manages block storage through three layers: Physical Volumes (PVs) are raw disks or partitions, Volume Groups (VGs) pool PVs into a shared storage namespace, and Logical Volumes (LVs) are virtual partitions carved from VG space. LVs support online resize, snapshots, mirroring, striping, thin provisioning, and VDO (dedup + compression).

All mutable device wrappers hold a .report field (frozen ReportModel) refreshed after state-changing operations.

LVM Base Classes

sts.lvm.base

LVM device base class.

Provides the shared command-execution contract for all LVM device types (PhysicalVolume, VolumeGroup, LogicalVolume, ThinPool): - _run: build and execute an LVM command, converting kwargs to CLI options - _target: the CLI identifier for a device (path, name, or vg/name)

LvmDevice pydantic-model

Bases: StorageDevice

Base class for LVM devices.

Show JSON schema:
{
  "additionalProperties": false,
  "description": "Base class for LVM devices.",
  "properties": {
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Path"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Size"
    },
    "model": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Model"
    }
  },
  "title": "LvmDevice",
  "type": "object"
}

Fields:

  • name (str | None)
  • path (PathOrStr | None)
  • size (int | None)
  • model (str | None)

Validators:

  • _derive_fields
Source code in sts_libs/src/sts/lvm/base.py
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
class LvmDevice(StorageDevice):
    """Base class for LVM devices."""

    # Optional parameters from parent classes
    name: str | None = None
    path: PathOrStr | None = None
    size: int | None = None
    model: str | None = None

    @model_validator(mode='after')
    def _derive_fields(self) -> Self:
        """Derive path from name, and name from path, when only one is provided."""
        if not self.path and self.name:
            self.path = Path(f'/dev/{self.name}')
        if self.path and not self.name:
            self.name = Path(self.path).name
        return self

    @property
    @abstractmethod
    def _target(self) -> str:
        """Return the CLI identifier for this device (path, name, or vg/name).

        Raises:
            LvmError: If the fields needed to address this device are not set.
        """

    def _run(self, cmd: str, *args: str | Path | None, **kwargs: Any) -> CommandResult:
        """Run an LVM command.

        Args:
            cmd: Command name (e.g. 'pvcreate')
        """
        argv = [cmd]
        if args:
            argv.extend(str(arg) for arg in args if arg)
        argv.extend(build_options(**kwargs))
        return run_argv(argv)

    @abstractmethod
    def create(
        self,
        *,
        yes: bool = True,
        force: bool = False,
        **options: Any,
    ) -> CommandResult:
        """Create LVM device."""

    @abstractmethod
    def remove(
        self,
        *,
        yes: bool = True,
        force: bool = False,
        **options: Any,
    ) -> CommandResult:
        """Remove LVM device."""

    @abstractmethod
    def refresh_report(self) -> bool:
        """Refresh the cached report snapshot for this device from the system."""

create(*, yes=True, force=False, **options) abstractmethod

Create LVM device.

Source code in sts_libs/src/sts/lvm/base.py
67
68
69
70
71
72
73
74
75
@abstractmethod
def create(
    self,
    *,
    yes: bool = True,
    force: bool = False,
    **options: Any,
) -> CommandResult:
    """Create LVM device."""

refresh_report() abstractmethod

Refresh the cached report snapshot for this device from the system.

Source code in sts_libs/src/sts/lvm/base.py
87
88
89
@abstractmethod
def refresh_report(self) -> bool:
    """Refresh the cached report snapshot for this device from the system."""

remove(*, yes=True, force=False, **options) abstractmethod

Remove LVM device.

Source code in sts_libs/src/sts/lvm/base.py
77
78
79
80
81
82
83
84
85
@abstractmethod
def remove(
    self,
    *,
    yes: bool = True,
    force: bool = False,
    **options: Any,
) -> CommandResult:
    """Remove LVM device."""

sts.lvm.logical_volume

LVM Logical Volume management.

A Logical Volume (LV) is a virtual partition carved out of a Volume Group's free space. LVs appear as block devices that can be formatted, mounted, resized, snapshotted, or converted between types (e.g. mirror, thin pool).

LogicalVolume pydantic-model

Bases: LvmDevice

Logical Volume device.

Example
lv = LogicalVolume(name='lv0', vg='vg0')
lv.create(size='100M').assert_ok()
print(lv.report.lv_size)
Show JSON schema:
{
  "$defs": {
    "LVReport": {
      "description": "Parsed LV data from 'lvs -o lv_all,seg_all --reportformat json'.\n\nFrozen (immutable) snapshot of one logical volume's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').\nAll fields match lvs JSON key names and retain str | None typing,\nexcept for a handful of numeric fields (see below) that are coerced.",
      "properties": {
        "lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Uuid"
        },
        "lv_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Name"
        },
        "lv_full_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Name"
        },
        "lv_path": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Path"
        },
        "lv_dm_path": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Dm Path"
        },
        "vg_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Name"
        },
        "lv_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Size"
        },
        "lv_metadata_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Metadata Size"
        },
        "seg_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Count"
        },
        "lv_layout": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Layout"
        },
        "lv_role": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Role"
        },
        "lv_attr": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Attr"
        },
        "lv_active": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active"
        },
        "lv_active_locally": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Locally"
        },
        "lv_active_remotely": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Remotely"
        },
        "lv_active_exclusively": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Exclusively"
        },
        "lv_permissions": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Permissions"
        },
        "lv_suspended": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Suspended"
        },
        "lv_major": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Major"
        },
        "lv_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Minor"
        },
        "lv_kernel_major": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Major"
        },
        "lv_kernel_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Minor"
        },
        "lv_read_ahead": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Read Ahead"
        },
        "lv_kernel_read_ahead": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Read Ahead"
        },
        "pool_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pool Lv"
        },
        "pool_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pool Lv Uuid"
        },
        "data_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Lv"
        },
        "data_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Lv Uuid"
        },
        "metadata_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Lv"
        },
        "metadata_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Lv Uuid"
        },
        "data_percent": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Percent"
        },
        "metadata_percent": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Percent"
        },
        "origin": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin"
        },
        "origin_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin Uuid"
        },
        "origin_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin Size"
        },
        "snap_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Snap Percent"
        },
        "raid_mismatch_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Mismatch Count"
        },
        "raid_sync_action": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Sync Action"
        },
        "raid_write_behind": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Write Behind"
        },
        "raid_min_recovery_rate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Min Recovery Rate"
        },
        "raid_max_recovery_rate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Max Recovery Rate"
        },
        "cache_total_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Total Blocks"
        },
        "cache_used_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Used Blocks"
        },
        "cache_dirty_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Dirty Blocks"
        },
        "cache_read_hits": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Read Hits"
        },
        "cache_read_misses": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Read Misses"
        },
        "cache_write_hits": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Write Hits"
        },
        "cache_write_misses": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Write Misses"
        },
        "kernel_cache_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Cache Settings"
        },
        "kernel_cache_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Cache Policy"
        },
        "vdo_operating_mode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Operating Mode"
        },
        "vdo_compression_state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Compression State"
        },
        "vdo_index_state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Index State"
        },
        "vdo_used_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Used Size"
        },
        "vdo_saving_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Saving Percent"
        },
        "writecache_block_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Block Size"
        },
        "writecache_total_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Total Blocks"
        },
        "writecache_free_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Free Blocks"
        },
        "writecache_writeback_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Writeback Blocks"
        },
        "writecache_error": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Error"
        },
        "lv_allocation_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Allocation Policy"
        },
        "lv_allocation_locked": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Allocation Locked"
        },
        "lv_autoactivation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Autoactivation"
        },
        "lv_when_full": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv When Full"
        },
        "lv_skip_activation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Skip Activation"
        },
        "lv_fixed_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Fixed Minor"
        },
        "lv_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Time"
        },
        "lv_time_removed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Time Removed"
        },
        "lv_host": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Host"
        },
        "lv_health_status": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Health Status"
        },
        "lv_check_needed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Check Needed"
        },
        "lv_merge_failed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Merge Failed"
        },
        "lv_snapshot_invalid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Snapshot Invalid"
        },
        "lv_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Tags"
        },
        "lv_profile": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Profile"
        },
        "lv_lockargs": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Lockargs"
        },
        "lv_modules": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Modules"
        },
        "lv_historical": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Historical"
        },
        "kernel_discards": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Discards"
        },
        "copy_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Copy Percent"
        },
        "sync_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Sync Percent"
        },
        "lv_live_table": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Live Table"
        },
        "lv_inactive_table": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Inactive Table"
        },
        "lv_device_open": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Device Open"
        },
        "lv_parent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Parent"
        },
        "lv_ancestors": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Ancestors"
        },
        "lv_full_ancestors": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Ancestors"
        },
        "lv_descendants": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Descendants"
        },
        "lv_full_descendants": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Descendants"
        },
        "lv_converting": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Converting"
        },
        "lv_merging": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Merging"
        },
        "move_pv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Move Pv"
        },
        "move_pv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Move Pv Uuid"
        },
        "convert_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Convert Lv"
        },
        "convert_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Convert Lv Uuid"
        },
        "mirror_log": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Mirror Log"
        },
        "mirror_log_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Mirror Log Uuid"
        },
        "lv_initial_image_sync": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Initial Image Sync"
        },
        "lv_image_synced": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Image Synced"
        },
        "raidintegritymode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raidintegritymode"
        },
        "raidintegrityblocksize": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raidintegrityblocksize"
        },
        "integritymismatches": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Integritymismatches"
        },
        "kernel_metadata_format": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Metadata Format"
        },
        "segtype": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Segtype"
        },
        "stripes": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Stripes"
        },
        "data_stripes": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Stripes"
        },
        "stripe_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Stripe Size"
        },
        "region_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Region Size"
        },
        "chunk_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Chunk Size"
        },
        "seg_start": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Start"
        },
        "seg_start_pe": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Start Pe"
        },
        "seg_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Size"
        },
        "seg_size_pe": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Size Pe"
        },
        "seg_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Tags"
        },
        "seg_pe_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Pe Ranges"
        },
        "seg_le_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Le Ranges"
        },
        "seg_metadata_le_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Metadata Le Ranges"
        },
        "devices": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Devices"
        },
        "metadata_devices": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Devices"
        },
        "seg_monitor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Monitor"
        },
        "reshape_len": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Reshape Len"
        },
        "reshape_len_le": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Reshape Len Le"
        },
        "data_copies": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Copies"
        },
        "data_offset": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Offset"
        },
        "new_data_offset": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "New Data Offset"
        },
        "parity_chunks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Parity Chunks"
        },
        "thin_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Thin Count"
        },
        "discards": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Discards"
        },
        "cache_metadata_format": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Metadata Format"
        },
        "cache_mode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Mode"
        },
        "zero": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Zero"
        },
        "transaction_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Transaction Id"
        },
        "thin_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Thin Id"
        },
        "cache_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Policy"
        },
        "cache_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Settings"
        },
        "integrity_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Integrity Settings"
        },
        "vdo_compression": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Compression"
        },
        "vdo_deduplication": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Deduplication"
        },
        "vdo_minimum_io_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Minimum Io Size"
        },
        "vdo_block_map_cache_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Block Map Cache Size"
        },
        "vdo_block_map_era_length": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Block Map Era Length"
        },
        "vdo_use_sparse_index": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Use Sparse Index"
        },
        "vdo_index_memory_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Index Memory Size"
        },
        "vdo_slab_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Slab Size"
        },
        "vdo_ack_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Ack Threads"
        },
        "vdo_bio_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Bio Threads"
        },
        "vdo_bio_rotation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Bio Rotation"
        },
        "vdo_cpu_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Cpu Threads"
        },
        "vdo_hash_zone_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Hash Zone Threads"
        },
        "vdo_logical_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Logical Threads"
        },
        "vdo_physical_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Physical Threads"
        },
        "vdo_max_discard": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Max Discard"
        },
        "vdo_header_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Header Size"
        },
        "vdo_use_metadata_hints": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Use Metadata Hints"
        },
        "vdo_write_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Write Policy"
        }
      },
      "title": "LVReport",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "Logical Volume device.\n\nExample:\n    ```python\n    lv = LogicalVolume(name='lv0', vg='vg0')\n    lv.create(size='100M').assert_ok()\n    print(lv.report.lv_size)\n    ```",
  "properties": {
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Path"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Size"
    },
    "model": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Model"
    },
    "vg": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg"
    },
    "pool_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pool Name"
    },
    "report": {
      "anyOf": [
        {
          "$ref": "#/$defs/LVReport"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "prevent_report_updates": {
      "default": false,
      "title": "Prevent Report Updates",
      "type": "boolean"
    }
  },
  "title": "LogicalVolume",
  "type": "object"
}

Fields:

  • path (PathOrStr | None)
  • name (str | None)
  • size (int | None)
  • model (str | None)
  • vg (str | None)
  • pool_name (str | None)
  • report (LVReport | None)
  • prevent_report_updates (bool)
Source code in sts_libs/src/sts/lvm/logical_volume.py
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
class LogicalVolume(LvmDevice):
    """Logical Volume device.

    Example:
        ```python
        lv = LogicalVolume(name='lv0', vg='vg0')
        lv.create(size='100M').assert_ok()
        print(lv.report.lv_size)
        ```
    """

    # Optional parameters for this class
    vg: str | None = None  # Parent VG
    pool_name: str | None = None
    report: LVReport | None = Field(default=None, repr=False)
    prevent_report_updates: bool = False

    @model_validator(mode='after')
    def _derive_fields(self) -> Self:
        """Derive path from name+vg, and name from path, when only one is provided.

        Note: unlike the generic ``LvmDevice`` derivation, this intentionally does
        NOT fall back to ``/dev/<name>`` when ``vg`` is missing — an LV path is only
        meaningful as ``/dev/<vg>/<name>``, so ``path`` stays unset until both
        ``name`` and ``vg`` are known.
        """
        if not self.path and self.name and self.vg:
            self.path = Path(f'/dev/{self.vg}/{self.name}')
        if self.path and not self.name:
            self.name = Path(self.path).name
        return self

    @property
    def _target(self) -> str:
        """Return the CLI identifier for this LV (vg/name).

        Raises:
            LvmError: If vg or name is not set.
        """
        if not self.vg:
            msg = 'vg is required'
            raise LvmError(msg)
        if not self.name:
            msg = 'name is required'
            raise LvmError(msg)
        return f'{self.vg}/{self.name}'

    def refresh_report(self) -> bool:
        """Refresh LV report data from the system."""
        if self.prevent_report_updates:
            return True
        if not self.name or not self.vg:
            return False
        report = fetch_lv_report(name=self.name, vg=self.vg)
        if report is None:
            return False
        self.report = report
        return True

    def discover_vg(self) -> str | None:
        """Discover the volume group for this LV by querying ``lvs``.

        Needed when an LV was constructed with a name but no VG (e.g., from a thin
        pool's ``pool_lv`` field which contains only the LV name).
        """
        if self.name and not self.vg:
            result = run_argv(['lvs', self.name, '-o', 'vg_name', '--noheadings'])
            if result.succeeded:
                self.vg = result.stdout.strip()
                return self.vg
        return None

    def create(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvCreateOptions],
    ) -> CommandResult:
        """Create Logical Volume.

        If pool_name is set, automatically adds ``--thinpool`` or ``--vdopool``
        depending on the volume type (``type='vdo'`` selects ``--vdopool``).

        Raises:
            LvmError: If name or vg is not set.

        Example:
            ```python
            lv = LogicalVolume(name='lv0', vg='vg0')
            lv.create(size='1G').assert_ok()

            # Thin volume (with pool_name set)
            thin_lv = LogicalVolume(name='thin1', vg='vg0', pool_name='pool1')
            thin_lv.create(virtualsize='500M').assert_ok()

            # VDO volume (with pool_name set)
            vdo_lv = LogicalVolume(name='vdo1', vg='vg0', pool_name='vdopool1')
            vdo_lv.create(type='vdo', size='8G').assert_ok()
            ```
        """
        if not self.name:
            msg = 'name is required'
            raise LvmError(msg)
        if not self.vg:
            msg = 'vg is required'
            raise LvmError(msg)

        # If pool_name is set, automatically add the appropriate pool option
        # Use --vdopool for VDO volumes, --thinpool for thin volumes
        if self.pool_name:
            lv_type = options.get('type', '')
            if lv_type == 'vdo' and 'vdopool' not in options:
                options = options | {'vdopool': self.pool_name}  # type: ignore[assignment]
            elif 'thinpool' not in options and lv_type != 'vdo':
                options = options | {'thinpool': self.pool_name}  # type: ignore[assignment]

        result = self._run('lvcreate', '-n', self.name, self.vg, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def remove(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvRemoveOptions],
    ) -> CommandResult:
        """Remove Logical Volume.

        Extra positional args are treated as additional volume paths for batch removal.

        Example:
            ```python
            lv = LogicalVolume(name='lv1', vg='vg0')
            lv.remove('vg0/lv2', 'vg0/lv3').assert_ok()
            ```
        """
        targets = [self._target, *args]
        return self._run('lvremove', *targets, yes=yes, force=force, **options)

    def change(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvChangeOptions],
    ) -> CommandResult:
        """Change Logical Volume attributes."""
        result = self._run('lvchange', *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def extend(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvExtendOptions],
    ) -> CommandResult:
        """Extend Logical Volume.

        Example:
            ```python
            lv = LogicalVolume(name='lvol0', vg='vg0')
            lv.extend(extents='100%vg').assert_ok()
            ```
        """
        result = self._run('lvextend', self._target, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def lvs(self, *args: str, **options: Unpack[LvsOptions]) -> CommandResult:
        """Run the ``lvs`` reporting command."""
        return self._run('lvs', *args, **options)

    def convert(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvConvertOptions],
    ) -> CommandResult:
        """Convert Logical Volume type."""
        result = self._run('lvconvert', self._target, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def convert_to_thinpool(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvConvertOptions],
    ) -> CommandResult:
        """Convert logical volume to thin pool via ``lvconvert --thinpool``.

        Example:
            ```python
            lv.convert_to_thinpool(chunksize='256k', zero='y', discards='nopassdown', poolmetadatasize='4M')

            # With separate metadata LV
            lv.convert_to_thinpool(poolmetadata='metadata_lv')
            ```
        """
        result = self._run('lvconvert', '--thinpool', self._target, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def convert_splitmirrors(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvConvertOptions],
    ) -> CommandResult:
        """Split images from a raid1 or mirror LV into a new LV.

        Example:
            ```python
            lv = LogicalVolume(name='mirror_lv', vg='vg0')
            result = lv.convert_splitmirrors('--splitmirrors', '1', '--name', 'split_lv')
            if result.succeeded:
                split_lv = LogicalVolume(name='split_lv', vg='vg0')
            ```
        """
        result = self._run('lvconvert', self._target, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def convert_originname(
        self,
        *args: str,
        thinpool: str,
        originname: str,
        lv_type: str = 'thin',
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvConvertOriginnameOptions],
    ) -> CommandResult:
        """Convert LV to thin LV with named external origin.

        The original LV becomes a read-only external origin under ``originname``,
        and a new thin LV is created in the given ``thinpool``.

        Example:
            ```python
            lv = LogicalVolume(name='data_lv', vg='vg0')
            lv.convert_originname(thinpool='vg0/thin_pool', originname='data_origin')
            origin_lv = LogicalVolume(name='data_origin', vg='vg0')
            ```
        """
        cmd_args = ['--type', lv_type]
        cmd_args.extend(['--thinpool', thinpool])
        cmd_args.extend(['--originname', originname])

        if args:
            cmd_args.extend(args)

        for key, value in options.items():
            cmd_args.extend([f'--{key}', str(value)])

        result = self._run('lvconvert', self._target, *cmd_args, yes=yes, force=force)
        if result.succeeded:
            self.refresh_report()
        return result

    def display(self, *args: str, **options: str) -> CommandResult:
        """Run ``lvdisplay`` for this LV."""
        if not self.vg or not self.name:
            return self._run('lvdisplay', *args, **options)
        return self._run('lvdisplay', f'{self.vg}/{self.name}', *args, **options)

    def reduce(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvReduceOptions],
    ) -> CommandResult:
        """Reduce Logical Volume size."""
        result = self._run('lvreduce', self._target, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def rename(
        self,
        new_name: str,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: str,
    ) -> CommandResult:
        """Rename Logical Volume.

        On success, updates ``self.name`` and ``self.path`` to reflect the new name.

        Raises:
            LvmError: If new_name is empty.
        """
        if not new_name:
            msg = 'new name is required'
            raise LvmError(msg)

        result = self._run('lvrename', self._target, new_name, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.name = new_name
            self.path = Path(f'/dev/{self.vg}/{self.name}')
            self.refresh_report()
        return result

    def resize(
        self,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvResizeOptions],
    ) -> CommandResult:
        """Resize Logical Volume (can grow or shrink)."""
        result = self._run('lvresize', self._target, *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def scan(self, *args: str, **options: str) -> CommandResult:
        """Run ``lvscan`` to discover LVs on all devices."""
        return self._run('lvscan', *args, **options)

    def deactivate(
        self,
        *,
        yes: bool = True,
        force: bool = False,
    ) -> CommandResult:
        """Deactivate Logical Volume.

        Waiting for deactivation is only meaningful if the lvchange itself
        succeeded, so failures raise immediately via assert_ok().
        """
        udevadm_settle()
        result = self.change('-an', self._target, yes=yes, force=force)
        result.assert_ok()
        udevadm_settle()
        self.wait_for_lv_deactivation()
        return result

    def activate(
        self,
        *,
        yes: bool = True,
        force: bool = False,
    ) -> CommandResult:
        """Activate Logical Volume."""
        return self.change('-ay', self._target, yes=yes, force=force)

    def wait_for_lv_deactivation(self, timeout: int = 30) -> None:
        """Wait for logical volume to be fully deactivated.

        Args:
            timeout: Maximum wait time in seconds

        Raises:
            LvmError: If deactivation times out.
        """
        start_time = time.time()

        while time.time() - start_time < timeout:
            # Dual check: lvs report may show inactive before the kernel removes the device node, or vice versa
            # Check LV status using lvs command
            self.refresh_report()
            logger.debug(self.report.lv_active if self.report else None)
            if self.report and self.report.lv_active != 'active':
                # LV is inactive - also verify device node is gone
                if self.path is not None:
                    device_path = Path(self.path)
                    if not device_path.exists():
                        return
                else:
                    return  # If no path, consider it deactivated
            time.sleep(2)  # Poll every 2 seconds

        raise LvmError(f'LV {self.vg}/{self.name} deactivation timed out after {timeout}s')

    def change_discards(
        self,
        *args: str,
        **options: Unpack[LvChangeOptions],
    ) -> CommandResult:
        """Change discards setting for logical volume.

        Raises:
            LvmError: If vg or name is not set.
        """
        if not self.vg or not self.name:
            msg = 'vg and name are required'
            raise LvmError(msg)

        return self.change(self._target, *args, **options)

    def create_snapshot(
        self,
        snapshot_name: str,
        *args: str,
        yes: bool = True,
        force: bool = False,
        **options: Unpack[LvCreateOptions],
    ) -> CommandResult:
        """Create snapshot of this LV.

        For thin LVs, creates thin snapshots. For regular LVs, creates COW snapshots.

        Raises:
            LvmError: If name, vg, or snapshot_name is not set.

        Example:
            ```python
            origin_lv.create_snapshot('snap1')
            snap1 = LogicalVolume(name='snap1', vg=origin_lv.vg)

            # COW snapshot with ignore activation skip
            origin_lv.create_snapshot('snap2', '-K', size='100M')
            ```
        """
        if not self.name:
            msg = 'name is required'
            raise LvmError(msg)
        if not self.vg:
            msg = 'vg is required'
            raise LvmError(msg)
        if not snapshot_name:
            msg = 'snapshot_name is required'
            raise LvmError(msg)

        cmd_args = ['-s']
        if args:
            cmd_args.extend(args)
        cmd_args.append(f'{self.vg}/{self.name}')
        cmd_args.extend(['-n', snapshot_name])

        result = self._run('lvcreate', *cmd_args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    @classmethod
    def from_report(cls, report: LVReport) -> LogicalVolume | None:
        """Create LogicalVolume from LVReport."""
        if not report.lv_name or not report.vg_name:
            return None

        # Already have a report -- skip auto-refresh to avoid re-fetching (or failing if LV was removed)
        return cls(
            name=report.lv_name,
            vg=report.vg_name,
            path=report.lv_path or None,
            report=report,
            prevent_report_updates=True,
        )

    @classmethod
    def get_all(cls, vg: str | None = None) -> list[LogicalVolume]:
        """Get all Logical Volumes."""
        logical_volumes: list[LogicalVolume] = []

        reports = fetch_all_lv_reports(vg)

        # Create LogicalVolumes from reports
        logical_volumes.extend(lv for report in reports if (lv := cls.from_report(report)))

        return logical_volumes

activate(*, yes=True, force=False)

Activate Logical Volume.

Source code in sts_libs/src/sts/lvm/logical_volume.py
399
400
401
402
403
404
405
406
def activate(
    self,
    *,
    yes: bool = True,
    force: bool = False,
) -> CommandResult:
    """Activate Logical Volume."""
    return self.change('-ay', self._target, yes=yes, force=force)

change(*args, yes=True, force=False, **options)

Change Logical Volume attributes.

Source code in sts_libs/src/sts/lvm/logical_volume.py
188
189
190
191
192
193
194
195
196
197
198
199
def change(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvChangeOptions],
) -> CommandResult:
    """Change Logical Volume attributes."""
    result = self._run('lvchange', *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

change_discards(*args, **options)

Change discards setting for logical volume.

Raises:

Type Description
LvmError

If vg or name is not set.

Source code in sts_libs/src/sts/lvm/logical_volume.py
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
def change_discards(
    self,
    *args: str,
    **options: Unpack[LvChangeOptions],
) -> CommandResult:
    """Change discards setting for logical volume.

    Raises:
        LvmError: If vg or name is not set.
    """
    if not self.vg or not self.name:
        msg = 'vg and name are required'
        raise LvmError(msg)

    return self.change(self._target, *args, **options)

convert(*args, yes=True, force=False, **options)

Convert Logical Volume type.

Source code in sts_libs/src/sts/lvm/logical_volume.py
225
226
227
228
229
230
231
232
233
234
235
236
def convert(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvConvertOptions],
) -> CommandResult:
    """Convert Logical Volume type."""
    result = self._run('lvconvert', self._target, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

convert_originname(*args, thinpool, originname, lv_type='thin', yes=True, force=False, **options)

Convert LV to thin LV with named external origin.

The original LV becomes a read-only external origin under originname, and a new thin LV is created in the given thinpool.

Example
lv = LogicalVolume(name='data_lv', vg='vg0')
lv.convert_originname(thinpool='vg0/thin_pool', originname='data_origin')
origin_lv = LogicalVolume(name='data_origin', vg='vg0')
Source code in sts_libs/src/sts/lvm/logical_volume.py
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
def convert_originname(
    self,
    *args: str,
    thinpool: str,
    originname: str,
    lv_type: str = 'thin',
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvConvertOriginnameOptions],
) -> CommandResult:
    """Convert LV to thin LV with named external origin.

    The original LV becomes a read-only external origin under ``originname``,
    and a new thin LV is created in the given ``thinpool``.

    Example:
        ```python
        lv = LogicalVolume(name='data_lv', vg='vg0')
        lv.convert_originname(thinpool='vg0/thin_pool', originname='data_origin')
        origin_lv = LogicalVolume(name='data_origin', vg='vg0')
        ```
    """
    cmd_args = ['--type', lv_type]
    cmd_args.extend(['--thinpool', thinpool])
    cmd_args.extend(['--originname', originname])

    if args:
        cmd_args.extend(args)

    for key, value in options.items():
        cmd_args.extend([f'--{key}', str(value)])

    result = self._run('lvconvert', self._target, *cmd_args, yes=yes, force=force)
    if result.succeeded:
        self.refresh_report()
    return result

convert_splitmirrors(*args, yes=True, force=False, **options)

Split images from a raid1 or mirror LV into a new LV.

Example
lv = LogicalVolume(name='mirror_lv', vg='vg0')
result = lv.convert_splitmirrors('--splitmirrors', '1', '--name', 'split_lv')
if result.succeeded:
    split_lv = LogicalVolume(name='split_lv', vg='vg0')
Source code in sts_libs/src/sts/lvm/logical_volume.py
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
def convert_splitmirrors(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvConvertOptions],
) -> CommandResult:
    """Split images from a raid1 or mirror LV into a new LV.

    Example:
        ```python
        lv = LogicalVolume(name='mirror_lv', vg='vg0')
        result = lv.convert_splitmirrors('--splitmirrors', '1', '--name', 'split_lv')
        if result.succeeded:
            split_lv = LogicalVolume(name='split_lv', vg='vg0')
        ```
    """
    result = self._run('lvconvert', self._target, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

convert_to_thinpool(*args, yes=True, force=False, **options)

Convert logical volume to thin pool via lvconvert --thinpool.

Example
lv.convert_to_thinpool(chunksize='256k', zero='y', discards='nopassdown', poolmetadatasize='4M')

# With separate metadata LV
lv.convert_to_thinpool(poolmetadata='metadata_lv')
Source code in sts_libs/src/sts/lvm/logical_volume.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
def convert_to_thinpool(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvConvertOptions],
) -> CommandResult:
    """Convert logical volume to thin pool via ``lvconvert --thinpool``.

    Example:
        ```python
        lv.convert_to_thinpool(chunksize='256k', zero='y', discards='nopassdown', poolmetadatasize='4M')

        # With separate metadata LV
        lv.convert_to_thinpool(poolmetadata='metadata_lv')
        ```
    """
    result = self._run('lvconvert', '--thinpool', self._target, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

create(*args, yes=True, force=False, **options)

Create Logical Volume.

If pool_name is set, automatically adds --thinpool or --vdopool depending on the volume type (type='vdo' selects --vdopool).

Raises:

Type Description
LvmError

If name or vg is not set.

Example
lv = LogicalVolume(name='lv0', vg='vg0')
lv.create(size='1G').assert_ok()

# Thin volume (with pool_name set)
thin_lv = LogicalVolume(name='thin1', vg='vg0', pool_name='pool1')
thin_lv.create(virtualsize='500M').assert_ok()

# VDO volume (with pool_name set)
vdo_lv = LogicalVolume(name='vdo1', vg='vg0', pool_name='vdopool1')
vdo_lv.create(type='vdo', size='8G').assert_ok()
Source code in sts_libs/src/sts/lvm/logical_volume.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def create(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvCreateOptions],
) -> CommandResult:
    """Create Logical Volume.

    If pool_name is set, automatically adds ``--thinpool`` or ``--vdopool``
    depending on the volume type (``type='vdo'`` selects ``--vdopool``).

    Raises:
        LvmError: If name or vg is not set.

    Example:
        ```python
        lv = LogicalVolume(name='lv0', vg='vg0')
        lv.create(size='1G').assert_ok()

        # Thin volume (with pool_name set)
        thin_lv = LogicalVolume(name='thin1', vg='vg0', pool_name='pool1')
        thin_lv.create(virtualsize='500M').assert_ok()

        # VDO volume (with pool_name set)
        vdo_lv = LogicalVolume(name='vdo1', vg='vg0', pool_name='vdopool1')
        vdo_lv.create(type='vdo', size='8G').assert_ok()
        ```
    """
    if not self.name:
        msg = 'name is required'
        raise LvmError(msg)
    if not self.vg:
        msg = 'vg is required'
        raise LvmError(msg)

    # If pool_name is set, automatically add the appropriate pool option
    # Use --vdopool for VDO volumes, --thinpool for thin volumes
    if self.pool_name:
        lv_type = options.get('type', '')
        if lv_type == 'vdo' and 'vdopool' not in options:
            options = options | {'vdopool': self.pool_name}  # type: ignore[assignment]
        elif 'thinpool' not in options and lv_type != 'vdo':
            options = options | {'thinpool': self.pool_name}  # type: ignore[assignment]

    result = self._run('lvcreate', '-n', self.name, self.vg, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

create_snapshot(snapshot_name, *args, yes=True, force=False, **options)

Create snapshot of this LV.

For thin LVs, creates thin snapshots. For regular LVs, creates COW snapshots.

Raises:

Type Description
LvmError

If name, vg, or snapshot_name is not set.

Example
origin_lv.create_snapshot('snap1')
snap1 = LogicalVolume(name='snap1', vg=origin_lv.vg)

# COW snapshot with ignore activation skip
origin_lv.create_snapshot('snap2', '-K', size='100M')
Source code in sts_libs/src/sts/lvm/logical_volume.py
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
def create_snapshot(
    self,
    snapshot_name: str,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvCreateOptions],
) -> CommandResult:
    """Create snapshot of this LV.

    For thin LVs, creates thin snapshots. For regular LVs, creates COW snapshots.

    Raises:
        LvmError: If name, vg, or snapshot_name is not set.

    Example:
        ```python
        origin_lv.create_snapshot('snap1')
        snap1 = LogicalVolume(name='snap1', vg=origin_lv.vg)

        # COW snapshot with ignore activation skip
        origin_lv.create_snapshot('snap2', '-K', size='100M')
        ```
    """
    if not self.name:
        msg = 'name is required'
        raise LvmError(msg)
    if not self.vg:
        msg = 'vg is required'
        raise LvmError(msg)
    if not snapshot_name:
        msg = 'snapshot_name is required'
        raise LvmError(msg)

    cmd_args = ['-s']
    if args:
        cmd_args.extend(args)
    cmd_args.append(f'{self.vg}/{self.name}')
    cmd_args.extend(['-n', snapshot_name])

    result = self._run('lvcreate', *cmd_args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

deactivate(*, yes=True, force=False)

Deactivate Logical Volume.

Waiting for deactivation is only meaningful if the lvchange itself succeeded, so failures raise immediately via assert_ok().

Source code in sts_libs/src/sts/lvm/logical_volume.py
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
def deactivate(
    self,
    *,
    yes: bool = True,
    force: bool = False,
) -> CommandResult:
    """Deactivate Logical Volume.

    Waiting for deactivation is only meaningful if the lvchange itself
    succeeded, so failures raise immediately via assert_ok().
    """
    udevadm_settle()
    result = self.change('-an', self._target, yes=yes, force=force)
    result.assert_ok()
    udevadm_settle()
    self.wait_for_lv_deactivation()
    return result

discover_vg()

Discover the volume group for this LV by querying lvs.

Needed when an LV was constructed with a name but no VG (e.g., from a thin pool's pool_lv field which contains only the LV name).

Source code in sts_libs/src/sts/lvm/logical_volume.py
105
106
107
108
109
110
111
112
113
114
115
116
def discover_vg(self) -> str | None:
    """Discover the volume group for this LV by querying ``lvs``.

    Needed when an LV was constructed with a name but no VG (e.g., from a thin
    pool's ``pool_lv`` field which contains only the LV name).
    """
    if self.name and not self.vg:
        result = run_argv(['lvs', self.name, '-o', 'vg_name', '--noheadings'])
        if result.succeeded:
            self.vg = result.stdout.strip()
            return self.vg
    return None

display(*args, **options)

Run lvdisplay for this LV.

Source code in sts_libs/src/sts/lvm/logical_volume.py
319
320
321
322
323
def display(self, *args: str, **options: str) -> CommandResult:
    """Run ``lvdisplay`` for this LV."""
    if not self.vg or not self.name:
        return self._run('lvdisplay', *args, **options)
    return self._run('lvdisplay', f'{self.vg}/{self.name}', *args, **options)

extend(*args, yes=True, force=False, **options)

Extend Logical Volume.

Example
lv = LogicalVolume(name='lvol0', vg='vg0')
lv.extend(extents='100%vg').assert_ok()
Source code in sts_libs/src/sts/lvm/logical_volume.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
def extend(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvExtendOptions],
) -> CommandResult:
    """Extend Logical Volume.

    Example:
        ```python
        lv = LogicalVolume(name='lvol0', vg='vg0')
        lv.extend(extents='100%vg').assert_ok()
        ```
    """
    result = self._run('lvextend', self._target, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

from_report(report) classmethod

Create LogicalVolume from LVReport.

Source code in sts_libs/src/sts/lvm/logical_volume.py
497
498
499
500
501
502
503
504
505
506
507
508
509
510
@classmethod
def from_report(cls, report: LVReport) -> LogicalVolume | None:
    """Create LogicalVolume from LVReport."""
    if not report.lv_name or not report.vg_name:
        return None

    # Already have a report -- skip auto-refresh to avoid re-fetching (or failing if LV was removed)
    return cls(
        name=report.lv_name,
        vg=report.vg_name,
        path=report.lv_path or None,
        report=report,
        prevent_report_updates=True,
    )

get_all(vg=None) classmethod

Get all Logical Volumes.

Source code in sts_libs/src/sts/lvm/logical_volume.py
512
513
514
515
516
517
518
519
520
521
522
@classmethod
def get_all(cls, vg: str | None = None) -> list[LogicalVolume]:
    """Get all Logical Volumes."""
    logical_volumes: list[LogicalVolume] = []

    reports = fetch_all_lv_reports(vg)

    # Create LogicalVolumes from reports
    logical_volumes.extend(lv for report in reports if (lv := cls.from_report(report)))

    return logical_volumes

lvs(*args, **options)

Run the lvs reporting command.

Source code in sts_libs/src/sts/lvm/logical_volume.py
221
222
223
def lvs(self, *args: str, **options: Unpack[LvsOptions]) -> CommandResult:
    """Run the ``lvs`` reporting command."""
    return self._run('lvs', *args, **options)

reduce(*args, yes=True, force=False, **options)

Reduce Logical Volume size.

Source code in sts_libs/src/sts/lvm/logical_volume.py
325
326
327
328
329
330
331
332
333
334
335
336
def reduce(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvReduceOptions],
) -> CommandResult:
    """Reduce Logical Volume size."""
    result = self._run('lvreduce', self._target, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

refresh_report()

Refresh LV report data from the system.

Source code in sts_libs/src/sts/lvm/logical_volume.py
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def refresh_report(self) -> bool:
    """Refresh LV report data from the system."""
    if self.prevent_report_updates:
        return True
    if not self.name or not self.vg:
        return False
    report = fetch_lv_report(name=self.name, vg=self.vg)
    if report is None:
        return False
    self.report = report
    return True

remove(*args, yes=True, force=False, **options)

Remove Logical Volume.

Extra positional args are treated as additional volume paths for batch removal.

Example
lv = LogicalVolume(name='lv1', vg='vg0')
lv.remove('vg0/lv2', 'vg0/lv3').assert_ok()
Source code in sts_libs/src/sts/lvm/logical_volume.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
def remove(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvRemoveOptions],
) -> CommandResult:
    """Remove Logical Volume.

    Extra positional args are treated as additional volume paths for batch removal.

    Example:
        ```python
        lv = LogicalVolume(name='lv1', vg='vg0')
        lv.remove('vg0/lv2', 'vg0/lv3').assert_ok()
        ```
    """
    targets = [self._target, *args]
    return self._run('lvremove', *targets, yes=yes, force=force, **options)

rename(new_name, *args, yes=True, force=False, **options)

Rename Logical Volume.

On success, updates self.name and self.path to reflect the new name.

Raises:

Type Description
LvmError

If new_name is empty.

Source code in sts_libs/src/sts/lvm/logical_volume.py
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
def rename(
    self,
    new_name: str,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: str,
) -> CommandResult:
    """Rename Logical Volume.

    On success, updates ``self.name`` and ``self.path`` to reflect the new name.

    Raises:
        LvmError: If new_name is empty.
    """
    if not new_name:
        msg = 'new name is required'
        raise LvmError(msg)

    result = self._run('lvrename', self._target, new_name, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.name = new_name
        self.path = Path(f'/dev/{self.vg}/{self.name}')
        self.refresh_report()
    return result

resize(*args, yes=True, force=False, **options)

Resize Logical Volume (can grow or shrink).

Source code in sts_libs/src/sts/lvm/logical_volume.py
364
365
366
367
368
369
370
371
372
373
374
375
def resize(
    self,
    *args: str,
    yes: bool = True,
    force: bool = False,
    **options: Unpack[LvResizeOptions],
) -> CommandResult:
    """Resize Logical Volume (can grow or shrink)."""
    result = self._run('lvresize', self._target, *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

scan(*args, **options)

Run lvscan to discover LVs on all devices.

Source code in sts_libs/src/sts/lvm/logical_volume.py
377
378
379
def scan(self, *args: str, **options: str) -> CommandResult:
    """Run ``lvscan`` to discover LVs on all devices."""
    return self._run('lvscan', *args, **options)

wait_for_lv_deactivation(timeout=30)

Wait for logical volume to be fully deactivated.

Parameters:

Name Type Description Default
timeout int

Maximum wait time in seconds

30

Raises:

Type Description
LvmError

If deactivation times out.

Source code in sts_libs/src/sts/lvm/logical_volume.py
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
def wait_for_lv_deactivation(self, timeout: int = 30) -> None:
    """Wait for logical volume to be fully deactivated.

    Args:
        timeout: Maximum wait time in seconds

    Raises:
        LvmError: If deactivation times out.
    """
    start_time = time.time()

    while time.time() - start_time < timeout:
        # Dual check: lvs report may show inactive before the kernel removes the device node, or vice versa
        # Check LV status using lvs command
        self.refresh_report()
        logger.debug(self.report.lv_active if self.report else None)
        if self.report and self.report.lv_active != 'active':
            # LV is inactive - also verify device node is gone
            if self.path is not None:
                device_path = Path(self.path)
                if not device_path.exists():
                    return
            else:
                return  # If no path, consider it deactivated
        time.sleep(2)  # Poll every 2 seconds

    raise LvmError(f'LV {self.vg}/{self.name} deactivation timed out after {timeout}s')

sts.lvm.physical_volume

LVM Physical Volume management.

A Physical Volume (PV) is a disk or partition initialized for use with LVM. PVs provide the storage pool that Volume Groups draw from.

PhysicalVolume pydantic-model

Bases: LvmDevice

Physical Volume device.

Show JSON schema:
{
  "$defs": {
    "PVReport": {
      "description": "Parsed PV data from 'pvs -o pv_all --reportformat json'.\n\nFrozen (immutable) snapshot of one physical volume's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').",
      "properties": {
        "pv_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Name"
        },
        "pv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Uuid"
        },
        "vg_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Name"
        },
        "pv_fmt": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Fmt"
        },
        "pv_attr": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Attr"
        },
        "pv_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Size"
        },
        "pv_free": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Free"
        },
        "pv_used": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Used"
        },
        "dev_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Dev Size"
        },
        "pv_major": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Major"
        },
        "pv_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Minor"
        },
        "pv_mda_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Mda Count"
        },
        "pv_mda_free": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Mda Free"
        },
        "pv_ba_start": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Ba Start"
        },
        "pv_ba_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Ba Size"
        },
        "pe_start": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pe Start"
        },
        "pv_pe_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Pe Count"
        },
        "pv_pe_alloc_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Pe Alloc Count"
        },
        "pv_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Tags"
        },
        "pv_allocatable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Allocatable"
        },
        "pv_exported": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Exported"
        },
        "pv_missing": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Missing"
        },
        "pv_in_use": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv In Use"
        },
        "pv_duplicate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Duplicate"
        }
      },
      "title": "PVReport",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "Physical Volume device.",
  "properties": {
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Path"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Size"
    },
    "model": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Model"
    },
    "vg": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg"
    },
    "report": {
      "anyOf": [
        {
          "$ref": "#/$defs/PVReport"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "prevent_report_updates": {
      "default": false,
      "title": "Prevent Report Updates",
      "type": "boolean"
    }
  },
  "title": "PhysicalVolume",
  "type": "object"
}

Fields:

  • path (PathOrStr | None)
  • name (str | None)
  • size (int | None)
  • model (str | None)
  • vg (str | None)
  • report (PVReport | None)
  • prevent_report_updates (bool)

Validators:

  • _derive_fields
Source code in sts_libs/src/sts/lvm/physical_volume.py
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
class PhysicalVolume(LvmDevice):
    """Physical Volume device."""

    # Optional parameters for this class
    vg: str | None = None  # Volume Group membership
    report: PVReport | None = Field(default=None, repr=False)
    prevent_report_updates: bool = False

    @property
    def _target(self) -> str:
        if not self.path:
            msg = 'path is required'
            raise LvmError(msg)
        return str(self.path)

    def refresh_report(self) -> bool:
        """Refresh PV report data from the system."""
        if self.prevent_report_updates:
            return True
        report = fetch_pv_report(self._target)
        if report is None:
            return False
        self.report = report
        return True

    def create(
        self,
        *,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[PvCreateOptions],
    ) -> CommandResult:
        """Create Physical Volume."""
        return self._run('pvcreate', self._target, yes=yes, force=force, **options)

    def remove(
        self,
        *,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[PvRemoveOptions],
    ) -> CommandResult:
        """Remove Physical Volume."""
        return self._run('pvremove', self._target, yes=yes, force=force, **options)

    @classmethod
    def from_blockdevice(
        cls,
        block_device: BlockDevice,
        *,
        create: bool = False,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[PvCreateOptions],
    ) -> PhysicalVolume:
        """Create PhysicalVolume from BlockDevice.

        When ``create=True``, also runs ``pvcreate`` to initialize the device.

        Raises:
            ValueError: If block_device has no path.
        """
        if not block_device.path:
            msg = 'BlockDevice must have a valid path'
            raise ValueError(msg)

        pv = cls(path=str(block_device.path), size=block_device.size, model=block_device.model)
        if create:
            pv.create(force=force, yes=yes, **options).assert_ok()
        return pv

    @classmethod
    def from_report(cls, report: PVReport) -> PhysicalVolume | None:
        """Create PhysicalVolume from PVReport."""
        if not report.pv_name:
            return None

        # Already have a report -- skip auto-refresh to avoid re-fetching (or failing if PV was removed)
        return cls(
            name=Path(report.pv_name).name,
            path=report.pv_name,
            report=report,
            prevent_report_updates=True,
        )

    @classmethod
    def get_all(cls) -> list[PhysicalVolume]:
        """Get all Physical Volumes."""
        return [pv for report in fetch_all_pv_reports() if (pv := cls.from_report(report))]

create(*, force=False, yes=True, **options)

Create Physical Volume.

Source code in sts_libs/src/sts/lvm/physical_volume.py
52
53
54
55
56
57
58
59
60
def create(
    self,
    *,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[PvCreateOptions],
) -> CommandResult:
    """Create Physical Volume."""
    return self._run('pvcreate', self._target, yes=yes, force=force, **options)

from_blockdevice(block_device, *, create=False, force=False, yes=True, **options) classmethod

Create PhysicalVolume from BlockDevice.

When create=True, also runs pvcreate to initialize the device.

Raises:

Type Description
ValueError

If block_device has no path.

Source code in sts_libs/src/sts/lvm/physical_volume.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
@classmethod
def from_blockdevice(
    cls,
    block_device: BlockDevice,
    *,
    create: bool = False,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[PvCreateOptions],
) -> PhysicalVolume:
    """Create PhysicalVolume from BlockDevice.

    When ``create=True``, also runs ``pvcreate`` to initialize the device.

    Raises:
        ValueError: If block_device has no path.
    """
    if not block_device.path:
        msg = 'BlockDevice must have a valid path'
        raise ValueError(msg)

    pv = cls(path=str(block_device.path), size=block_device.size, model=block_device.model)
    if create:
        pv.create(force=force, yes=yes, **options).assert_ok()
    return pv

from_report(report) classmethod

Create PhysicalVolume from PVReport.

Source code in sts_libs/src/sts/lvm/physical_volume.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
@classmethod
def from_report(cls, report: PVReport) -> PhysicalVolume | None:
    """Create PhysicalVolume from PVReport."""
    if not report.pv_name:
        return None

    # Already have a report -- skip auto-refresh to avoid re-fetching (or failing if PV was removed)
    return cls(
        name=Path(report.pv_name).name,
        path=report.pv_name,
        report=report,
        prevent_report_updates=True,
    )

get_all() classmethod

Get all Physical Volumes.

Source code in sts_libs/src/sts/lvm/physical_volume.py
112
113
114
115
@classmethod
def get_all(cls) -> list[PhysicalVolume]:
    """Get all Physical Volumes."""
    return [pv for report in fetch_all_pv_reports() if (pv := cls.from_report(report))]

refresh_report()

Refresh PV report data from the system.

Source code in sts_libs/src/sts/lvm/physical_volume.py
42
43
44
45
46
47
48
49
50
def refresh_report(self) -> bool:
    """Refresh PV report data from the system."""
    if self.prevent_report_updates:
        return True
    report = fetch_pv_report(self._target)
    if report is None:
        return False
    self.report = report
    return True

remove(*, force=False, yes=True, **options)

Remove Physical Volume.

Source code in sts_libs/src/sts/lvm/physical_volume.py
62
63
64
65
66
67
68
69
70
def remove(
    self,
    *,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[PvRemoveOptions],
) -> CommandResult:
    """Remove Physical Volume."""
    return self._run('pvremove', self._target, yes=yes, force=force, **options)

sts.lvm.volume_group

LVM Volume Group management.

A Volume Group (VG) combines Physical Volumes into a storage pool that can be divided into Logical Volumes.

VolumeGroup pydantic-model

Bases: LvmDevice

Volume Group device.

Show JSON schema:
{
  "$defs": {
    "VGReport": {
      "description": "Parsed VG data from 'vgs -o vg_all --reportformat json'.\n\nFrozen (immutable) snapshot of one volume group's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').",
      "properties": {
        "vg_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Name"
        },
        "vg_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Uuid"
        },
        "vg_fmt": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Fmt"
        },
        "vg_attr": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Attr"
        },
        "vg_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Size"
        },
        "vg_free": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Free"
        },
        "vg_extent_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Extent Size"
        },
        "vg_extent_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Extent Count"
        },
        "vg_free_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Free Count"
        },
        "pv_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pv Count"
        },
        "lv_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Count"
        },
        "snap_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Snap Count"
        },
        "vg_seqno": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Seqno"
        },
        "vg_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Tags"
        },
        "vg_mda_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Mda Count"
        },
        "vg_mda_free": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Mda Free"
        },
        "max_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Max Lv"
        },
        "max_pv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Max Pv"
        },
        "vg_permissions": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Permissions"
        },
        "vg_allocation_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Allocation Policy"
        },
        "vg_clustered": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Clustered"
        },
        "vg_exported": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Exported"
        },
        "vg_partial": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Partial"
        },
        "vg_missing_pv_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Missing Pv Count"
        }
      },
      "title": "VGReport",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "Volume Group device.",
  "properties": {
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Path"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Size"
    },
    "model": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Model"
    },
    "pvs": {
      "items": {
        "type": "string"
      },
      "title": "Pvs",
      "type": "array"
    },
    "report": {
      "anyOf": [
        {
          "$ref": "#/$defs/VGReport"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "prevent_report_updates": {
      "default": false,
      "title": "Prevent Report Updates",
      "type": "boolean"
    }
  },
  "title": "VolumeGroup",
  "type": "object"
}

Fields:

  • path (PathOrStr | None)
  • name (str | None)
  • size (int | None)
  • model (str | None)
  • pvs (list[str])
  • report (VGReport | None)
  • prevent_report_updates (bool)

Validators:

  • _derive_fields
  • _coerce_pvs_to_strpvs
Source code in sts_libs/src/sts/lvm/volume_group.py
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class VolumeGroup(LvmDevice):
    """Volume Group device."""

    # Optional parameters for this class
    pvs: list[str] = Field(default_factory=list)  # Member PVs
    report: VGReport | None = Field(default=None, repr=False)
    prevent_report_updates: bool = False

    @field_validator('pvs', mode='before')
    @classmethod
    def _coerce_pvs_to_str(cls, v: list[str | Path]) -> list[str]:
        return [str(p) for p in v]

    @property
    def _target(self) -> str:
        if not self.name:
            msg = 'name is required'
            raise LvmError(msg)
        return self.name

    def refresh_report(self) -> bool:
        """Refresh VG report data from the system."""
        if self.prevent_report_updates:
            return True
        report = fetch_vg_report(self._target)
        if report is None:
            return False
        self.report = report
        return True

    def create(
        self,
        *,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[VgCreateOptions],
    ) -> CommandResult:
        """Create Volume Group from its configured PVs.

        Raises:
            LvmError: If no PVs are configured.
        """
        if not self.pvs:
            msg = 'physical volumes required'
            raise LvmError(msg)
        return self._run('vgcreate', self._target, *self.pvs, yes=yes, force=force, **options)

    def remove(
        self,
        *,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[VgRemoveOptions],
    ) -> CommandResult:
        """Remove Volume Group."""
        return self._run('vgremove', self._target, yes=yes, force=force, **options)

    def activate(
        self,
        *,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[VgChangeOptions],
    ) -> CommandResult:
        """Activate Volume Group and all its LVs."""
        return self._run('vgchange', '-a', 'y', self._target, yes=yes, force=force, **options)

    def deactivate(
        self,
        *,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[VgChangeOptions],
    ) -> CommandResult:
        """Deactivate Volume Group and all its LVs."""
        return self._run('vgchange', '-a', 'n', self._target, yes=yes, force=force, **options)

    @classmethod
    def from_report(cls, report: VGReport) -> VolumeGroup | None:
        """Create VolumeGroup from VGReport."""
        if not report.vg_name:
            return None

        # Already have a report -- skip auto-refresh to avoid re-fetching (or failing if VG was removed)
        return cls(
            name=report.vg_name,
            report=report,
            prevent_report_updates=True,
        )

    @classmethod
    def get_all(cls) -> list[VolumeGroup]:
        """Get all Volume Groups."""
        return [vg for report in fetch_all_vg_reports() if (vg := cls.from_report(report))]

activate(*, force=False, yes=True, **options)

Activate Volume Group and all its LVs.

Source code in sts_libs/src/sts/lvm/volume_group.py
84
85
86
87
88
89
90
91
92
def activate(
    self,
    *,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[VgChangeOptions],
) -> CommandResult:
    """Activate Volume Group and all its LVs."""
    return self._run('vgchange', '-a', 'y', self._target, yes=yes, force=force, **options)

create(*, force=False, yes=True, **options)

Create Volume Group from its configured PVs.

Raises:

Type Description
LvmError

If no PVs are configured.

Source code in sts_libs/src/sts/lvm/volume_group.py
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
def create(
    self,
    *,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[VgCreateOptions],
) -> CommandResult:
    """Create Volume Group from its configured PVs.

    Raises:
        LvmError: If no PVs are configured.
    """
    if not self.pvs:
        msg = 'physical volumes required'
        raise LvmError(msg)
    return self._run('vgcreate', self._target, *self.pvs, yes=yes, force=force, **options)

deactivate(*, force=False, yes=True, **options)

Deactivate Volume Group and all its LVs.

Source code in sts_libs/src/sts/lvm/volume_group.py
 94
 95
 96
 97
 98
 99
100
101
102
def deactivate(
    self,
    *,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[VgChangeOptions],
) -> CommandResult:
    """Deactivate Volume Group and all its LVs."""
    return self._run('vgchange', '-a', 'n', self._target, yes=yes, force=force, **options)

from_report(report) classmethod

Create VolumeGroup from VGReport.

Source code in sts_libs/src/sts/lvm/volume_group.py
104
105
106
107
108
109
110
111
112
113
114
115
@classmethod
def from_report(cls, report: VGReport) -> VolumeGroup | None:
    """Create VolumeGroup from VGReport."""
    if not report.vg_name:
        return None

    # Already have a report -- skip auto-refresh to avoid re-fetching (or failing if VG was removed)
    return cls(
        name=report.vg_name,
        report=report,
        prevent_report_updates=True,
    )

get_all() classmethod

Get all Volume Groups.

Source code in sts_libs/src/sts/lvm/volume_group.py
117
118
119
120
@classmethod
def get_all(cls) -> list[VolumeGroup]:
    """Get all Volume Groups."""
    return [vg for report in fetch_all_vg_reports() if (vg := cls.from_report(report))]

refresh_report()

Refresh VG report data from the system.

Source code in sts_libs/src/sts/lvm/volume_group.py
47
48
49
50
51
52
53
54
55
def refresh_report(self) -> bool:
    """Refresh VG report data from the system."""
    if self.prevent_report_updates:
        return True
    report = fetch_vg_report(self._target)
    if report is None:
        return False
    self.report = report
    return True

remove(*, force=False, yes=True, **options)

Remove Volume Group.

Source code in sts_libs/src/sts/lvm/volume_group.py
74
75
76
77
78
79
80
81
82
def remove(
    self,
    *,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[VgRemoveOptions],
) -> CommandResult:
    """Remove Volume Group."""
    return self._run('vgremove', self._target, yes=yes, force=force, **options)

sts.lvm.thin_pool

LVM Thin Pool management.

A Thin Pool is a special Logical Volume that provides thin provisioning: it manages a tdata (data) and tmeta (metadata) component and holds multiple thin volumes that share the pool's space dynamically.

Example
pool = ThinPool(name='pool1', vg='vg0')
pool.create(size='1G')

thin_lv1 = pool.create_thin_volume('thin1', virtualsize='500M')
thin_lv2 = pool.create_thin_volume('thin2', virtualsize='800M')

data_usage, meta_usage = pool.get_pool_usage()
tdata = pool.get_tdata_volume()
tmeta = pool.get_tmeta_volume()

ThinPool pydantic-model

Bases: LogicalVolume

Thin Pool logical volume.

Show JSON schema:
{
  "$defs": {
    "LVReport": {
      "description": "Parsed LV data from 'lvs -o lv_all,seg_all --reportformat json'.\n\nFrozen (immutable) snapshot of one logical volume's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').\nAll fields match lvs JSON key names and retain str | None typing,\nexcept for a handful of numeric fields (see below) that are coerced.",
      "properties": {
        "lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Uuid"
        },
        "lv_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Name"
        },
        "lv_full_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Name"
        },
        "lv_path": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Path"
        },
        "lv_dm_path": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Dm Path"
        },
        "vg_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg Name"
        },
        "lv_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Size"
        },
        "lv_metadata_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Metadata Size"
        },
        "seg_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Count"
        },
        "lv_layout": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Layout"
        },
        "lv_role": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Role"
        },
        "lv_attr": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Attr"
        },
        "lv_active": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active"
        },
        "lv_active_locally": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Locally"
        },
        "lv_active_remotely": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Remotely"
        },
        "lv_active_exclusively": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Active Exclusively"
        },
        "lv_permissions": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Permissions"
        },
        "lv_suspended": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Suspended"
        },
        "lv_major": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Major"
        },
        "lv_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Minor"
        },
        "lv_kernel_major": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Major"
        },
        "lv_kernel_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Minor"
        },
        "lv_read_ahead": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Read Ahead"
        },
        "lv_kernel_read_ahead": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Kernel Read Ahead"
        },
        "pool_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pool Lv"
        },
        "pool_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pool Lv Uuid"
        },
        "data_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Lv"
        },
        "data_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Lv Uuid"
        },
        "metadata_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Lv"
        },
        "metadata_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Lv Uuid"
        },
        "data_percent": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Percent"
        },
        "metadata_percent": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Percent"
        },
        "origin": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin"
        },
        "origin_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin Uuid"
        },
        "origin_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Origin Size"
        },
        "snap_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Snap Percent"
        },
        "raid_mismatch_count": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Mismatch Count"
        },
        "raid_sync_action": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Sync Action"
        },
        "raid_write_behind": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Write Behind"
        },
        "raid_min_recovery_rate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Min Recovery Rate"
        },
        "raid_max_recovery_rate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raid Max Recovery Rate"
        },
        "cache_total_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Total Blocks"
        },
        "cache_used_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Used Blocks"
        },
        "cache_dirty_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Dirty Blocks"
        },
        "cache_read_hits": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Read Hits"
        },
        "cache_read_misses": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Read Misses"
        },
        "cache_write_hits": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Write Hits"
        },
        "cache_write_misses": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Write Misses"
        },
        "kernel_cache_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Cache Settings"
        },
        "kernel_cache_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Cache Policy"
        },
        "vdo_operating_mode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Operating Mode"
        },
        "vdo_compression_state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Compression State"
        },
        "vdo_index_state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Index State"
        },
        "vdo_used_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Used Size"
        },
        "vdo_saving_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Saving Percent"
        },
        "writecache_block_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Block Size"
        },
        "writecache_total_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Total Blocks"
        },
        "writecache_free_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Free Blocks"
        },
        "writecache_writeback_blocks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Writeback Blocks"
        },
        "writecache_error": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Writecache Error"
        },
        "lv_allocation_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Allocation Policy"
        },
        "lv_allocation_locked": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Allocation Locked"
        },
        "lv_autoactivation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Autoactivation"
        },
        "lv_when_full": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv When Full"
        },
        "lv_skip_activation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Skip Activation"
        },
        "lv_fixed_minor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Fixed Minor"
        },
        "lv_time": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Time"
        },
        "lv_time_removed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Time Removed"
        },
        "lv_host": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Host"
        },
        "lv_health_status": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Health Status"
        },
        "lv_check_needed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Check Needed"
        },
        "lv_merge_failed": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Merge Failed"
        },
        "lv_snapshot_invalid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Snapshot Invalid"
        },
        "lv_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Tags"
        },
        "lv_profile": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Profile"
        },
        "lv_lockargs": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Lockargs"
        },
        "lv_modules": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Modules"
        },
        "lv_historical": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Historical"
        },
        "kernel_discards": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Discards"
        },
        "copy_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Copy Percent"
        },
        "sync_percent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Sync Percent"
        },
        "lv_live_table": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Live Table"
        },
        "lv_inactive_table": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Inactive Table"
        },
        "lv_device_open": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Device Open"
        },
        "lv_parent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Parent"
        },
        "lv_ancestors": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Ancestors"
        },
        "lv_full_ancestors": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Ancestors"
        },
        "lv_descendants": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Descendants"
        },
        "lv_full_descendants": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Full Descendants"
        },
        "lv_converting": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Converting"
        },
        "lv_merging": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Merging"
        },
        "move_pv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Move Pv"
        },
        "move_pv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Move Pv Uuid"
        },
        "convert_lv": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Convert Lv"
        },
        "convert_lv_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Convert Lv Uuid"
        },
        "mirror_log": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Mirror Log"
        },
        "mirror_log_uuid": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Mirror Log Uuid"
        },
        "lv_initial_image_sync": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Initial Image Sync"
        },
        "lv_image_synced": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lv Image Synced"
        },
        "raidintegritymode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raidintegritymode"
        },
        "raidintegrityblocksize": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Raidintegrityblocksize"
        },
        "integritymismatches": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Integritymismatches"
        },
        "kernel_metadata_format": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Kernel Metadata Format"
        },
        "segtype": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Segtype"
        },
        "stripes": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Stripes"
        },
        "data_stripes": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Stripes"
        },
        "stripe_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Stripe Size"
        },
        "region_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Region Size"
        },
        "chunk_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Chunk Size"
        },
        "seg_start": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Start"
        },
        "seg_start_pe": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Start Pe"
        },
        "seg_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Size"
        },
        "seg_size_pe": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Size Pe"
        },
        "seg_tags": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Tags"
        },
        "seg_pe_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Pe Ranges"
        },
        "seg_le_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Le Ranges"
        },
        "seg_metadata_le_ranges": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Metadata Le Ranges"
        },
        "devices": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Devices"
        },
        "metadata_devices": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Metadata Devices"
        },
        "seg_monitor": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Seg Monitor"
        },
        "reshape_len": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Reshape Len"
        },
        "reshape_len_le": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Reshape Len Le"
        },
        "data_copies": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Copies"
        },
        "data_offset": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Data Offset"
        },
        "new_data_offset": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "New Data Offset"
        },
        "parity_chunks": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Parity Chunks"
        },
        "thin_count": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Thin Count"
        },
        "discards": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Discards"
        },
        "cache_metadata_format": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Metadata Format"
        },
        "cache_mode": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Mode"
        },
        "zero": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Zero"
        },
        "transaction_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Transaction Id"
        },
        "thin_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Thin Id"
        },
        "cache_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Policy"
        },
        "cache_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Cache Settings"
        },
        "integrity_settings": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Integrity Settings"
        },
        "vdo_compression": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Compression"
        },
        "vdo_deduplication": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Deduplication"
        },
        "vdo_minimum_io_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Minimum Io Size"
        },
        "vdo_block_map_cache_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Block Map Cache Size"
        },
        "vdo_block_map_era_length": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Block Map Era Length"
        },
        "vdo_use_sparse_index": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Use Sparse Index"
        },
        "vdo_index_memory_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Index Memory Size"
        },
        "vdo_slab_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Slab Size"
        },
        "vdo_ack_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Ack Threads"
        },
        "vdo_bio_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Bio Threads"
        },
        "vdo_bio_rotation": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Bio Rotation"
        },
        "vdo_cpu_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Cpu Threads"
        },
        "vdo_hash_zone_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Hash Zone Threads"
        },
        "vdo_logical_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Logical Threads"
        },
        "vdo_physical_threads": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Physical Threads"
        },
        "vdo_max_discard": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Max Discard"
        },
        "vdo_header_size": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Header Size"
        },
        "vdo_use_metadata_hints": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Use Metadata Hints"
        },
        "vdo_write_policy": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vdo Write Policy"
        }
      },
      "title": "LVReport",
      "type": "object"
    },
    "LogicalVolume": {
      "additionalProperties": false,
      "description": "Logical Volume device.\n\nExample:\n    ```python\n    lv = LogicalVolume(name='lv0', vg='vg0')\n    lv.create(size='100M').assert_ok()\n    print(lv.report.lv_size)\n    ```",
      "properties": {
        "path": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "format": "path",
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Path"
        },
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Name"
        },
        "size": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Size"
        },
        "model": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Model"
        },
        "vg": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Vg"
        },
        "pool_name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Pool Name"
        },
        "report": {
          "anyOf": [
            {
              "$ref": "#/$defs/LVReport"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "prevent_report_updates": {
          "default": false,
          "title": "Prevent Report Updates",
          "type": "boolean"
        }
      },
      "title": "LogicalVolume",
      "type": "object"
    }
  },
  "additionalProperties": false,
  "description": "Thin Pool logical volume.",
  "properties": {
    "path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "format": "path",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Path"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "size": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Size"
    },
    "model": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Model"
    },
    "vg": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg"
    },
    "pool_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pool Name"
    },
    "report": {
      "anyOf": [
        {
          "$ref": "#/$defs/LVReport"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "prevent_report_updates": {
      "default": false,
      "title": "Prevent Report Updates",
      "type": "boolean"
    },
    "thin_volumes": {
      "items": {
        "$ref": "#/$defs/LogicalVolume"
      },
      "title": "Thin Volumes",
      "type": "array"
    },
    "tdata": {
      "anyOf": [
        {
          "$ref": "#/$defs/LogicalVolume"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "tmeta": {
      "anyOf": [
        {
          "$ref": "#/$defs/LogicalVolume"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    }
  },
  "title": "ThinPool",
  "type": "object"
}

Fields:

  • path (PathOrStr | None)
  • name (str | None)
  • size (int | None)
  • model (str | None)
  • vg (str | None)
  • pool_name (str | None)
  • report (LVReport | None)
  • prevent_report_updates (bool)
  • thin_volumes (list[LogicalVolume])
  • tdata (LogicalVolume | None)
  • tmeta (LogicalVolume | None)
Source code in sts_libs/src/sts/lvm/thin_pool.py
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
class ThinPool(LogicalVolume):
    """Thin Pool logical volume."""

    thin_volumes: list[LogicalVolume] = Field(default_factory=list, repr=False)
    tdata: LogicalVolume | None = None
    tmeta: LogicalVolume | None = None

    def refresh_report(self) -> bool:
        """Refresh Thin Pool LV report data.

        Also populates tdata and tmeta component references and refreshes
        their reports.
        """
        if self.prevent_report_updates:
            return True
        success = super().refresh_report()
        if success:
            if self.get_tdata_volume() and self.tdata:
                self.tdata.refresh_report()
            if self.get_tmeta_volume() and self.tmeta:
                self.tmeta.refresh_report()
        return success

    def create(
        self,
        *args: str,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[LvCreateOptions],
    ) -> CommandResult:
        """Create Thin Pool logical volume.

        Always sets type='thin-pool', overriding whatever the caller passes.
        """
        options['type'] = 'thin-pool'
        return super().create(*args, force=force, yes=yes, **options)

    def discover_thin_volumes(self) -> list[LogicalVolume]:
        """Discover thin volumes in this pool."""
        self.thin_volumes = []
        all_lvs = LogicalVolume.get_all(self.vg)
        for lv in all_lvs:
            if (
                lv.report
                and lv.report.pool_lv
                and lv.report.pool_lv.strip('[]') == self.name
                and lv.report.lv_layout
                and 'thin' in lv.report.lv_layout
            ):
                self.thin_volumes.append(lv)
        return self.thin_volumes

    def get_tdata_volume(self) -> LogicalVolume | None:
        """Get the tdata (data) component of the thin pool."""
        if not self.name or not self.vg:
            return None
        data_lv_name = f'{self.name}_tdata'
        if self.tdata:
            return self.tdata
        try:
            self.tdata = LogicalVolume(name=data_lv_name, vg=self.vg)
        except (ValueError, OSError) as e:
            logger.warning(f'Failed to get tdata volume {data_lv_name}: {e}')
            return None
        else:
            return self.tdata

    def get_tmeta_volume(self) -> LogicalVolume | None:
        """Get the tmeta (metadata) component of the thin pool."""
        if not self.name or not self.vg:
            return None
        meta_lv_name = f'{self.name}_tmeta'
        if self.tmeta:
            return self.tmeta
        try:
            self.tmeta = LogicalVolume(name=meta_lv_name, vg=self.vg)
        except (ValueError, OSError) as e:
            logger.warning(f'Failed to get tmeta volume {meta_lv_name}: {e}')
            return None
        else:
            return self.tmeta

    def convert_pool_data(
        self,
        *args: str,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[LvConvertOptions],
    ) -> CommandResult:
        """Convert thin pool data component (e.g. add RAID1 mirroring)."""
        result = self._run('lvconvert', f'{self._target}_tdata', *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def convert_pool_metadata(
        self,
        *args: str,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[LvConvertOptions],
    ) -> CommandResult:
        """Convert thin pool metadata component (e.g. add RAID1 mirroring)."""
        result = self._run('lvconvert', f'{self._target}_tmeta', *args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def swap_metadata(
        self,
        metadata_lv: str,
        *args: str,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[LvConvertOptions],
    ) -> CommandResult:
        """Swap thin pool metadata with another LV (for repair workflows)."""
        result = self._run(
            'lvconvert',
            '--thinpool',
            self._target,
            '--poolmetadata',
            metadata_lv,
            *args,
            yes=yes,
            force=force,
            **options,
        )
        if result.succeeded:
            self.refresh_report()
        return result

    def repair(
        self,
        pv_device: str | None = None,
        *args: str,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[LvConvertOptions],
    ) -> CommandResult:
        """Repair thin pool metadata via lvconvert --repair."""
        cmd_args = ['--repair', self._target]
        if pv_device:
            cmd_args.append(pv_device)
        if args:
            cmd_args.extend(args)
        result = self._run('lvconvert', *cmd_args, yes=yes, force=force, **options)
        if result.succeeded:
            self.refresh_report()
        return result

    def get_pool_usage(self) -> tuple[float | None, float | None]:
        """Get thin pool data and metadata usage percentages.

        Returns:
            Tuple of (data_percent, metadata_percent) as floats,
            or None for a field that couldn't be read.
        """
        self.refresh_report()
        if self.report:
            return self.report.data_percent, self.report.metadata_percent
        return None, None

    def get_data_stripes(self) -> int | None:
        """Get stripe count for thin pool data component (lives on tdata, not the pool LV)."""
        self.refresh_report()
        if self.tdata and self.tdata.report:
            return self.tdata.report.stripes
        return None

    def get_data_stripe_size(self) -> str | None:
        """Get stripe size for thin pool data component (lives on tdata, not the pool LV)."""
        self.refresh_report()
        if self.tdata and self.tdata.report:
            return self.tdata.report.stripe_size
        return None

    def create_thin_volume(self, lv_name: str, *args: str, **options: Unpack[LvCreateOptions]) -> LogicalVolume:
        """Create thin volume in this pool."""
        thin_lv = LogicalVolume(name=lv_name, pool_name=self.name, vg=self.vg)
        thin_lv.create(*args, **options).assert_ok()
        self.refresh_report()
        self.thin_volumes.append(thin_lv)
        return thin_lv

    def get_thin_volume_count(self) -> int:
        """Get the number of thin volumes in this pool."""
        if self.report and self.report.thin_count is not None:
            return self.report.thin_count
        return len(self.thin_volumes)

    @classmethod
    def create_thin_pool(cls, pool_name: str, vg_name: str, *args: str, **options: Unpack[LvCreateOptions]) -> ThinPool:
        """Create thin pool with specified options."""
        pool = cls(name=pool_name, vg=vg_name)
        pool.create(*args, **options).assert_ok()
        return pool

    def remove_thin_volumes(self, *, force: bool = True) -> Self:
        """Remove all thin volumes in this pool."""
        self.discover_thin_volumes()
        if not self.thin_volumes:
            logger.debug(f'No thin volumes found in pool {self.name}')
            return self
        for thin_lv in self.thin_volumes:
            logger.debug(f'Removing thin volume {thin_lv.name} from pool {self.name}')
            if force:
                thin_lv.remove(force=True, yes=True).assert_ok()
            else:
                thin_lv.remove().assert_ok()
        self.thin_volumes = []
        return self

    def remove_with_thin_volumes(
        self,
        *args: str,
        force: bool = False,
        yes: bool = True,
        **options: Unpack[LvRemoveOptions],
    ) -> CommandResult:
        """Remove thin pool along with all its thin volumes."""
        self.remove_thin_volumes(force=force)
        return self.remove(*args, force=force, yes=yes, **options)

    def __str__(self) -> str:
        """String representation of ThinPool."""
        return f"ThinPool(name='{self.name}', vg='{self.vg}', thin_volumes={self.get_thin_volume_count()})"

__str__()

String representation of ThinPool.

Source code in sts_libs/src/sts/lvm/thin_pool.py
264
265
266
def __str__(self) -> str:
    """String representation of ThinPool."""
    return f"ThinPool(name='{self.name}', vg='{self.vg}', thin_volumes={self.get_thin_volume_count()})"

convert_pool_data(*args, force=False, yes=True, **options)

Convert thin pool data component (e.g. add RAID1 mirroring).

Source code in sts_libs/src/sts/lvm/thin_pool.py
122
123
124
125
126
127
128
129
130
131
132
133
def convert_pool_data(
    self,
    *args: str,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[LvConvertOptions],
) -> CommandResult:
    """Convert thin pool data component (e.g. add RAID1 mirroring)."""
    result = self._run('lvconvert', f'{self._target}_tdata', *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

convert_pool_metadata(*args, force=False, yes=True, **options)

Convert thin pool metadata component (e.g. add RAID1 mirroring).

Source code in sts_libs/src/sts/lvm/thin_pool.py
135
136
137
138
139
140
141
142
143
144
145
146
def convert_pool_metadata(
    self,
    *args: str,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[LvConvertOptions],
) -> CommandResult:
    """Convert thin pool metadata component (e.g. add RAID1 mirroring)."""
    result = self._run('lvconvert', f'{self._target}_tmeta', *args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

create(*args, force=False, yes=True, **options)

Create Thin Pool logical volume.

Always sets type='thin-pool', overriding whatever the caller passes.

Source code in sts_libs/src/sts/lvm/thin_pool.py
63
64
65
66
67
68
69
70
71
72
73
74
75
def create(
    self,
    *args: str,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[LvCreateOptions],
) -> CommandResult:
    """Create Thin Pool logical volume.

    Always sets type='thin-pool', overriding whatever the caller passes.
    """
    options['type'] = 'thin-pool'
    return super().create(*args, force=force, yes=yes, **options)

create_thin_pool(pool_name, vg_name, *args, **options) classmethod

Create thin pool with specified options.

Source code in sts_libs/src/sts/lvm/thin_pool.py
231
232
233
234
235
236
@classmethod
def create_thin_pool(cls, pool_name: str, vg_name: str, *args: str, **options: Unpack[LvCreateOptions]) -> ThinPool:
    """Create thin pool with specified options."""
    pool = cls(name=pool_name, vg=vg_name)
    pool.create(*args, **options).assert_ok()
    return pool

create_thin_volume(lv_name, *args, **options)

Create thin volume in this pool.

Source code in sts_libs/src/sts/lvm/thin_pool.py
217
218
219
220
221
222
223
def create_thin_volume(self, lv_name: str, *args: str, **options: Unpack[LvCreateOptions]) -> LogicalVolume:
    """Create thin volume in this pool."""
    thin_lv = LogicalVolume(name=lv_name, pool_name=self.name, vg=self.vg)
    thin_lv.create(*args, **options).assert_ok()
    self.refresh_report()
    self.thin_volumes.append(thin_lv)
    return thin_lv

discover_thin_volumes()

Discover thin volumes in this pool.

Source code in sts_libs/src/sts/lvm/thin_pool.py
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def discover_thin_volumes(self) -> list[LogicalVolume]:
    """Discover thin volumes in this pool."""
    self.thin_volumes = []
    all_lvs = LogicalVolume.get_all(self.vg)
    for lv in all_lvs:
        if (
            lv.report
            and lv.report.pool_lv
            and lv.report.pool_lv.strip('[]') == self.name
            and lv.report.lv_layout
            and 'thin' in lv.report.lv_layout
        ):
            self.thin_volumes.append(lv)
    return self.thin_volumes

get_data_stripe_size()

Get stripe size for thin pool data component (lives on tdata, not the pool LV).

Source code in sts_libs/src/sts/lvm/thin_pool.py
210
211
212
213
214
215
def get_data_stripe_size(self) -> str | None:
    """Get stripe size for thin pool data component (lives on tdata, not the pool LV)."""
    self.refresh_report()
    if self.tdata and self.tdata.report:
        return self.tdata.report.stripe_size
    return None

get_data_stripes()

Get stripe count for thin pool data component (lives on tdata, not the pool LV).

Source code in sts_libs/src/sts/lvm/thin_pool.py
203
204
205
206
207
208
def get_data_stripes(self) -> int | None:
    """Get stripe count for thin pool data component (lives on tdata, not the pool LV)."""
    self.refresh_report()
    if self.tdata and self.tdata.report:
        return self.tdata.report.stripes
    return None

get_pool_usage()

Get thin pool data and metadata usage percentages.

Returns:

Type Description
float | None

Tuple of (data_percent, metadata_percent) as floats,

float | None

or None for a field that couldn't be read.

Source code in sts_libs/src/sts/lvm/thin_pool.py
191
192
193
194
195
196
197
198
199
200
201
def get_pool_usage(self) -> tuple[float | None, float | None]:
    """Get thin pool data and metadata usage percentages.

    Returns:
        Tuple of (data_percent, metadata_percent) as floats,
        or None for a field that couldn't be read.
    """
    self.refresh_report()
    if self.report:
        return self.report.data_percent, self.report.metadata_percent
    return None, None

get_tdata_volume()

Get the tdata (data) component of the thin pool.

Source code in sts_libs/src/sts/lvm/thin_pool.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
def get_tdata_volume(self) -> LogicalVolume | None:
    """Get the tdata (data) component of the thin pool."""
    if not self.name or not self.vg:
        return None
    data_lv_name = f'{self.name}_tdata'
    if self.tdata:
        return self.tdata
    try:
        self.tdata = LogicalVolume(name=data_lv_name, vg=self.vg)
    except (ValueError, OSError) as e:
        logger.warning(f'Failed to get tdata volume {data_lv_name}: {e}')
        return None
    else:
        return self.tdata

get_thin_volume_count()

Get the number of thin volumes in this pool.

Source code in sts_libs/src/sts/lvm/thin_pool.py
225
226
227
228
229
def get_thin_volume_count(self) -> int:
    """Get the number of thin volumes in this pool."""
    if self.report and self.report.thin_count is not None:
        return self.report.thin_count
    return len(self.thin_volumes)

get_tmeta_volume()

Get the tmeta (metadata) component of the thin pool.

Source code in sts_libs/src/sts/lvm/thin_pool.py
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def get_tmeta_volume(self) -> LogicalVolume | None:
    """Get the tmeta (metadata) component of the thin pool."""
    if not self.name or not self.vg:
        return None
    meta_lv_name = f'{self.name}_tmeta'
    if self.tmeta:
        return self.tmeta
    try:
        self.tmeta = LogicalVolume(name=meta_lv_name, vg=self.vg)
    except (ValueError, OSError) as e:
        logger.warning(f'Failed to get tmeta volume {meta_lv_name}: {e}')
        return None
    else:
        return self.tmeta

refresh_report()

Refresh Thin Pool LV report data.

Also populates tdata and tmeta component references and refreshes their reports.

Source code in sts_libs/src/sts/lvm/thin_pool.py
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def refresh_report(self) -> bool:
    """Refresh Thin Pool LV report data.

    Also populates tdata and tmeta component references and refreshes
    their reports.
    """
    if self.prevent_report_updates:
        return True
    success = super().refresh_report()
    if success:
        if self.get_tdata_volume() and self.tdata:
            self.tdata.refresh_report()
        if self.get_tmeta_volume() and self.tmeta:
            self.tmeta.refresh_report()
    return success

remove_thin_volumes(*, force=True)

Remove all thin volumes in this pool.

Source code in sts_libs/src/sts/lvm/thin_pool.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
def remove_thin_volumes(self, *, force: bool = True) -> Self:
    """Remove all thin volumes in this pool."""
    self.discover_thin_volumes()
    if not self.thin_volumes:
        logger.debug(f'No thin volumes found in pool {self.name}')
        return self
    for thin_lv in self.thin_volumes:
        logger.debug(f'Removing thin volume {thin_lv.name} from pool {self.name}')
        if force:
            thin_lv.remove(force=True, yes=True).assert_ok()
        else:
            thin_lv.remove().assert_ok()
    self.thin_volumes = []
    return self

remove_with_thin_volumes(*args, force=False, yes=True, **options)

Remove thin pool along with all its thin volumes.

Source code in sts_libs/src/sts/lvm/thin_pool.py
253
254
255
256
257
258
259
260
261
262
def remove_with_thin_volumes(
    self,
    *args: str,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[LvRemoveOptions],
) -> CommandResult:
    """Remove thin pool along with all its thin volumes."""
    self.remove_thin_volumes(force=force)
    return self.remove(*args, force=force, yes=yes, **options)

repair(pv_device=None, *args, force=False, yes=True, **options)

Repair thin pool metadata via lvconvert --repair.

Source code in sts_libs/src/sts/lvm/thin_pool.py
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def repair(
    self,
    pv_device: str | None = None,
    *args: str,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[LvConvertOptions],
) -> CommandResult:
    """Repair thin pool metadata via lvconvert --repair."""
    cmd_args = ['--repair', self._target]
    if pv_device:
        cmd_args.append(pv_device)
    if args:
        cmd_args.extend(args)
    result = self._run('lvconvert', *cmd_args, yes=yes, force=force, **options)
    if result.succeeded:
        self.refresh_report()
    return result

swap_metadata(metadata_lv, *args, force=False, yes=True, **options)

Swap thin pool metadata with another LV (for repair workflows).

Source code in sts_libs/src/sts/lvm/thin_pool.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def swap_metadata(
    self,
    metadata_lv: str,
    *args: str,
    force: bool = False,
    yes: bool = True,
    **options: Unpack[LvConvertOptions],
) -> CommandResult:
    """Swap thin pool metadata with another LV (for repair workflows)."""
    result = self._run(
        'lvconvert',
        '--thinpool',
        self._target,
        '--poolmetadata',
        metadata_lv,
        *args,
        yes=yes,
        force=force,
        **options,
    )
    if result.succeeded:
        self.refresh_report()
    return result

LVM Reports and Configuration

sts.lvm.reports

LVM report handling.

Provides LVReport, PVReport, and VGReport (frozen Pydantic models) for typed parsing of 'lvs', 'pvs', and 'vgs' JSON output, plus fetch functions that run the respective command and return validated models.

Each report is a frozen (immutable) snapshot of one device's state from the corresponding LVM report command. The mutable device wrapper classes (in logical_volume.py, physical_volume.py, volume_group.py) hold a reference to a report and refresh it after state-changing operations. This separation ensures report data is always a consistent point-in-time snapshot.

LVReport pydantic-model

Bases: ReportModel

Parsed LV data from 'lvs -o lv_all,seg_all --reportformat json'.

Frozen (immutable) snapshot of one logical volume's report fields. Unknown JSON keys are silently ignored (extra='ignore'). All fields match lvs JSON key names and retain str | None typing, except for a handful of numeric fields (see below) that are coerced.

Show JSON schema:
{
  "description": "Parsed LV data from 'lvs -o lv_all,seg_all --reportformat json'.\n\nFrozen (immutable) snapshot of one logical volume's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').\nAll fields match lvs JSON key names and retain str | None typing,\nexcept for a handful of numeric fields (see below) that are coerced.",
  "properties": {
    "lv_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Uuid"
    },
    "lv_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Name"
    },
    "lv_full_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Full Name"
    },
    "lv_path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Path"
    },
    "lv_dm_path": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Dm Path"
    },
    "vg_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Name"
    },
    "lv_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Size"
    },
    "lv_metadata_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Metadata Size"
    },
    "seg_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Count"
    },
    "lv_layout": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Layout"
    },
    "lv_role": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Role"
    },
    "lv_attr": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Attr"
    },
    "lv_active": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Active"
    },
    "lv_active_locally": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Active Locally"
    },
    "lv_active_remotely": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Active Remotely"
    },
    "lv_active_exclusively": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Active Exclusively"
    },
    "lv_permissions": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Permissions"
    },
    "lv_suspended": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Suspended"
    },
    "lv_major": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Major"
    },
    "lv_minor": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Minor"
    },
    "lv_kernel_major": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Kernel Major"
    },
    "lv_kernel_minor": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Kernel Minor"
    },
    "lv_read_ahead": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Read Ahead"
    },
    "lv_kernel_read_ahead": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Kernel Read Ahead"
    },
    "pool_lv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pool Lv"
    },
    "pool_lv_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pool Lv Uuid"
    },
    "data_lv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Data Lv"
    },
    "data_lv_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Data Lv Uuid"
    },
    "metadata_lv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Metadata Lv"
    },
    "metadata_lv_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Metadata Lv Uuid"
    },
    "data_percent": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Data Percent"
    },
    "metadata_percent": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Metadata Percent"
    },
    "origin": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Origin"
    },
    "origin_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Origin Uuid"
    },
    "origin_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Origin Size"
    },
    "snap_percent": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Snap Percent"
    },
    "raid_mismatch_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Raid Mismatch Count"
    },
    "raid_sync_action": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Raid Sync Action"
    },
    "raid_write_behind": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Raid Write Behind"
    },
    "raid_min_recovery_rate": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Raid Min Recovery Rate"
    },
    "raid_max_recovery_rate": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Raid Max Recovery Rate"
    },
    "cache_total_blocks": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Total Blocks"
    },
    "cache_used_blocks": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Used Blocks"
    },
    "cache_dirty_blocks": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Dirty Blocks"
    },
    "cache_read_hits": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Read Hits"
    },
    "cache_read_misses": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Read Misses"
    },
    "cache_write_hits": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Write Hits"
    },
    "cache_write_misses": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Write Misses"
    },
    "kernel_cache_settings": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Kernel Cache Settings"
    },
    "kernel_cache_policy": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Kernel Cache Policy"
    },
    "vdo_operating_mode": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Operating Mode"
    },
    "vdo_compression_state": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Compression State"
    },
    "vdo_index_state": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Index State"
    },
    "vdo_used_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Used Size"
    },
    "vdo_saving_percent": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Saving Percent"
    },
    "writecache_block_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Writecache Block Size"
    },
    "writecache_total_blocks": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Writecache Total Blocks"
    },
    "writecache_free_blocks": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Writecache Free Blocks"
    },
    "writecache_writeback_blocks": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Writecache Writeback Blocks"
    },
    "writecache_error": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Writecache Error"
    },
    "lv_allocation_policy": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Allocation Policy"
    },
    "lv_allocation_locked": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Allocation Locked"
    },
    "lv_autoactivation": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Autoactivation"
    },
    "lv_when_full": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv When Full"
    },
    "lv_skip_activation": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Skip Activation"
    },
    "lv_fixed_minor": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Fixed Minor"
    },
    "lv_time": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Time"
    },
    "lv_time_removed": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Time Removed"
    },
    "lv_host": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Host"
    },
    "lv_health_status": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Health Status"
    },
    "lv_check_needed": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Check Needed"
    },
    "lv_merge_failed": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Merge Failed"
    },
    "lv_snapshot_invalid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Snapshot Invalid"
    },
    "lv_tags": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Tags"
    },
    "lv_profile": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Profile"
    },
    "lv_lockargs": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Lockargs"
    },
    "lv_modules": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Modules"
    },
    "lv_historical": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Historical"
    },
    "kernel_discards": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Kernel Discards"
    },
    "copy_percent": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Copy Percent"
    },
    "sync_percent": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Sync Percent"
    },
    "lv_live_table": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Live Table"
    },
    "lv_inactive_table": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Inactive Table"
    },
    "lv_device_open": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Device Open"
    },
    "lv_parent": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Parent"
    },
    "lv_ancestors": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Ancestors"
    },
    "lv_full_ancestors": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Full Ancestors"
    },
    "lv_descendants": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Descendants"
    },
    "lv_full_descendants": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Full Descendants"
    },
    "lv_converting": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Converting"
    },
    "lv_merging": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Merging"
    },
    "move_pv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Move Pv"
    },
    "move_pv_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Move Pv Uuid"
    },
    "convert_lv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Convert Lv"
    },
    "convert_lv_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Convert Lv Uuid"
    },
    "mirror_log": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Mirror Log"
    },
    "mirror_log_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Mirror Log Uuid"
    },
    "lv_initial_image_sync": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Initial Image Sync"
    },
    "lv_image_synced": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Image Synced"
    },
    "raidintegritymode": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Raidintegritymode"
    },
    "raidintegrityblocksize": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Raidintegrityblocksize"
    },
    "integritymismatches": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Integritymismatches"
    },
    "kernel_metadata_format": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Kernel Metadata Format"
    },
    "segtype": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Segtype"
    },
    "stripes": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Stripes"
    },
    "data_stripes": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Data Stripes"
    },
    "stripe_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Stripe Size"
    },
    "region_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Region Size"
    },
    "chunk_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Chunk Size"
    },
    "seg_start": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Start"
    },
    "seg_start_pe": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Start Pe"
    },
    "seg_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Size"
    },
    "seg_size_pe": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Size Pe"
    },
    "seg_tags": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Tags"
    },
    "seg_pe_ranges": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Pe Ranges"
    },
    "seg_le_ranges": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Le Ranges"
    },
    "seg_metadata_le_ranges": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Metadata Le Ranges"
    },
    "devices": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Devices"
    },
    "metadata_devices": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Metadata Devices"
    },
    "seg_monitor": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Seg Monitor"
    },
    "reshape_len": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Reshape Len"
    },
    "reshape_len_le": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Reshape Len Le"
    },
    "data_copies": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Data Copies"
    },
    "data_offset": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Data Offset"
    },
    "new_data_offset": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "New Data Offset"
    },
    "parity_chunks": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Parity Chunks"
    },
    "thin_count": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Thin Count"
    },
    "discards": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Discards"
    },
    "cache_metadata_format": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Metadata Format"
    },
    "cache_mode": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Mode"
    },
    "zero": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Zero"
    },
    "transaction_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Transaction Id"
    },
    "thin_id": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Thin Id"
    },
    "cache_policy": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Policy"
    },
    "cache_settings": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Cache Settings"
    },
    "integrity_settings": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Integrity Settings"
    },
    "vdo_compression": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Compression"
    },
    "vdo_deduplication": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Deduplication"
    },
    "vdo_minimum_io_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Minimum Io Size"
    },
    "vdo_block_map_cache_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Block Map Cache Size"
    },
    "vdo_block_map_era_length": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Block Map Era Length"
    },
    "vdo_use_sparse_index": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Use Sparse Index"
    },
    "vdo_index_memory_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Index Memory Size"
    },
    "vdo_slab_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Slab Size"
    },
    "vdo_ack_threads": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Ack Threads"
    },
    "vdo_bio_threads": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Bio Threads"
    },
    "vdo_bio_rotation": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Bio Rotation"
    },
    "vdo_cpu_threads": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Cpu Threads"
    },
    "vdo_hash_zone_threads": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Hash Zone Threads"
    },
    "vdo_logical_threads": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Logical Threads"
    },
    "vdo_physical_threads": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Physical Threads"
    },
    "vdo_max_discard": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Max Discard"
    },
    "vdo_header_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Header Size"
    },
    "vdo_use_metadata_hints": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Use Metadata Hints"
    },
    "vdo_write_policy": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vdo Write Policy"
    }
  },
  "title": "LVReport",
  "type": "object"
}

Fields:

  • lv_uuid (str | None)
  • lv_name (str | None)
  • lv_full_name (str | None)
  • lv_path (str | None)
  • lv_dm_path (str | None)
  • vg_name (str | None)
  • lv_size (str | None)
  • lv_metadata_size (str | None)
  • seg_count (str | None)
  • lv_layout (str | None)
  • lv_role (str | None)
  • lv_attr (str | None)
  • lv_active (str | None)
  • lv_active_locally (str | None)
  • lv_active_remotely (str | None)
  • lv_active_exclusively (str | None)
  • lv_permissions (str | None)
  • lv_suspended (str | None)
  • lv_major (str | None)
  • lv_minor (str | None)
  • lv_kernel_major (str | None)
  • lv_kernel_minor (str | None)
  • lv_read_ahead (str | None)
  • lv_kernel_read_ahead (str | None)
  • pool_lv (str | None)
  • pool_lv_uuid (str | None)
  • data_lv (str | None)
  • data_lv_uuid (str | None)
  • metadata_lv (str | None)
  • metadata_lv_uuid (str | None)
  • data_percent (float | None)
  • metadata_percent (float | None)
  • origin (str | None)
  • origin_uuid (str | None)
  • origin_size (str | None)
  • snap_percent (str | None)
  • raid_mismatch_count (str | None)
  • raid_sync_action (str | None)
  • raid_write_behind (str | None)
  • raid_min_recovery_rate (str | None)
  • raid_max_recovery_rate (str | None)
  • cache_total_blocks (str | None)
  • cache_used_blocks (str | None)
  • cache_dirty_blocks (str | None)
  • cache_read_hits (str | None)
  • cache_read_misses (str | None)
  • cache_write_hits (str | None)
  • cache_write_misses (str | None)
  • kernel_cache_settings (str | None)
  • kernel_cache_policy (str | None)
  • vdo_operating_mode (str | None)
  • vdo_compression_state (str | None)
  • vdo_index_state (str | None)
  • vdo_used_size (str | None)
  • vdo_saving_percent (str | None)
  • writecache_block_size (str | None)
  • writecache_total_blocks (str | None)
  • writecache_free_blocks (str | None)
  • writecache_writeback_blocks (str | None)
  • writecache_error (str | None)
  • lv_allocation_policy (str | None)
  • lv_allocation_locked (str | None)
  • lv_autoactivation (str | None)
  • lv_when_full (str | None)
  • lv_skip_activation (str | None)
  • lv_fixed_minor (str | None)
  • lv_time (str | None)
  • lv_time_removed (str | None)
  • lv_host (str | None)
  • lv_health_status (str | None)
  • lv_check_needed (str | None)
  • lv_merge_failed (str | None)
  • lv_snapshot_invalid (str | None)
  • lv_tags (str | None)
  • lv_profile (str | None)
  • lv_lockargs (str | None)
  • lv_modules (str | None)
  • lv_historical (str | None)
  • kernel_discards (str | None)
  • copy_percent (str | None)
  • sync_percent (str | None)
  • lv_live_table (str | None)
  • lv_inactive_table (str | None)
  • lv_device_open (str | None)
  • lv_parent (str | None)
  • lv_ancestors (str | None)
  • lv_full_ancestors (str | None)
  • lv_descendants (str | None)
  • lv_full_descendants (str | None)
  • lv_converting (str | None)
  • lv_merging (str | None)
  • move_pv (str | None)
  • move_pv_uuid (str | None)
  • convert_lv (str | None)
  • convert_lv_uuid (str | None)
  • mirror_log (str | None)
  • mirror_log_uuid (str | None)
  • lv_initial_image_sync (str | None)
  • lv_image_synced (str | None)
  • raidintegritymode (str | None)
  • raidintegrityblocksize (str | None)
  • integritymismatches (str | None)
  • kernel_metadata_format (str | None)
  • segtype (str | None)
  • stripes (int | None)
  • data_stripes (str | None)
  • stripe_size (str | None)
  • region_size (str | None)
  • chunk_size (str | None)
  • seg_start (str | None)
  • seg_start_pe (str | None)
  • seg_size (str | None)
  • seg_size_pe (str | None)
  • seg_tags (str | None)
  • seg_pe_ranges (str | None)
  • seg_le_ranges (str | None)
  • seg_metadata_le_ranges (str | None)
  • devices (str | None)
  • metadata_devices (str | None)
  • seg_monitor (str | None)
  • reshape_len (str | None)
  • reshape_len_le (str | None)
  • data_copies (str | None)
  • data_offset (str | None)
  • new_data_offset (str | None)
  • parity_chunks (str | None)
  • thin_count (int | None)
  • discards (str | None)
  • cache_metadata_format (str | None)
  • cache_mode (str | None)
  • zero (str | None)
  • transaction_id (str | None)
  • thin_id (str | None)
  • cache_policy (str | None)
  • cache_settings (str | None)
  • integrity_settings (str | None)
  • vdo_compression (str | None)
  • vdo_deduplication (str | None)
  • vdo_minimum_io_size (str | None)
  • vdo_block_map_cache_size (str | None)
  • vdo_block_map_era_length (str | None)
  • vdo_use_sparse_index (str | None)
  • vdo_index_memory_size (str | None)
  • vdo_slab_size (str | None)
  • vdo_ack_threads (str | None)
  • vdo_bio_threads (str | None)
  • vdo_bio_rotation (str | None)
  • vdo_cpu_threads (str | None)
  • vdo_hash_zone_threads (str | None)
  • vdo_logical_threads (str | None)
  • vdo_physical_threads (str | None)
  • vdo_max_discard (str | None)
  • vdo_header_size (str | None)
  • vdo_use_metadata_hints (str | None)
  • vdo_write_policy (str | None)

Validators:

  • _derive_vg_name
  • _coerce_percentdata_percent, metadata_percent
  • _coerce_intthin_count, stripes
Source code in sts_libs/src/sts/lvm/reports.py
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
class LVReport(ReportModel):
    """Parsed LV data from 'lvs -o lv_all,seg_all --reportformat json'.

    Frozen (immutable) snapshot of one logical volume's report fields.
    Unknown JSON keys are silently ignored (extra='ignore').
    All fields match lvs JSON key names and retain str | None typing,
    except for a handful of numeric fields (see below) that are coerced.
    """

    # Most commonly used fields: lv_name, vg_name, lv_path (identification), lv_size, lv_attr, lv_active (status).
    # For thin provisioning: pool_lv, data_percent. All fields are str | None because lvs returns everything as text.

    # Core LV identification
    lv_uuid: str | None = None
    lv_name: str | None = None
    lv_full_name: str | None = None
    lv_path: str | None = None
    lv_dm_path: str | None = None
    vg_name: str | None = None

    @model_validator(mode='before')
    @classmethod
    def _derive_vg_name(cls, data: dict[str, Any]) -> dict[str, Any]:
        """Derive vg_name from lv_full_name when not provided by lvs."""
        if not data.get('vg_name'):
            full_name = data.get('lv_full_name', '')
            if full_name and '/' in full_name:
                data['vg_name'] = full_name.split('/', 1)[0]
        return data

    @field_validator('data_percent', 'metadata_percent', mode='before')
    @classmethod
    def _coerce_percent(cls, v: str | float | None) -> float | None:
        """Coerce lvs percent fields ('12.34' or '') to float | None."""
        if v in (None, ''):
            return None
        try:
            return float(v)
        except (TypeError, ValueError):
            return None

    @field_validator('thin_count', 'stripes', mode='before')
    @classmethod
    def _coerce_int(cls, v: str | int | None) -> int | None:
        """Coerce lvs integer-like fields ('3' or '') to int | None."""
        if v in (None, ''):
            return None
        try:
            return int(v)
        except (TypeError, ValueError):
            return None

    # Size and layout information
    lv_size: str | None = None
    lv_metadata_size: str | None = None
    seg_count: str | None = None
    lv_layout: str | None = None
    lv_role: str | None = None

    # Status and attributes
    lv_attr: str | None = None
    lv_active: str | None = None
    lv_active_locally: str | None = None
    lv_active_remotely: str | None = None
    lv_active_exclusively: str | None = None
    lv_permissions: str | None = None
    lv_suspended: str | None = None

    # Device information
    lv_major: str | None = None
    lv_minor: str | None = None
    lv_kernel_major: str | None = None
    lv_kernel_minor: str | None = None
    lv_read_ahead: str | None = None
    lv_kernel_read_ahead: str | None = None

    # Pool and thin provisioning
    pool_lv: str | None = None
    pool_lv_uuid: str | None = None
    data_lv: str | None = None
    data_lv_uuid: str | None = None
    metadata_lv: str | None = None
    metadata_lv_uuid: str | None = None
    data_percent: float | None = None
    metadata_percent: float | None = None

    # Snapshot information
    origin: str | None = None
    origin_uuid: str | None = None
    origin_size: str | None = None
    snap_percent: str | None = None

    # RAID information
    raid_mismatch_count: str | None = None
    raid_sync_action: str | None = None
    raid_write_behind: str | None = None
    raid_min_recovery_rate: str | None = None
    raid_max_recovery_rate: str | None = None

    # Cache information
    cache_total_blocks: str | None = None
    cache_used_blocks: str | None = None
    cache_dirty_blocks: str | None = None
    cache_read_hits: str | None = None
    cache_read_misses: str | None = None
    cache_write_hits: str | None = None
    cache_write_misses: str | None = None
    kernel_cache_settings: str | None = None
    kernel_cache_policy: str | None = None

    # VDO information
    vdo_operating_mode: str | None = None
    vdo_compression_state: str | None = None
    vdo_index_state: str | None = None
    vdo_used_size: str | None = None
    vdo_saving_percent: str | None = None

    # Write cache information
    writecache_block_size: str | None = None
    writecache_total_blocks: str | None = None
    writecache_free_blocks: str | None = None
    writecache_writeback_blocks: str | None = None
    writecache_error: str | None = None

    # Configuration and policy
    lv_allocation_policy: str | None = None
    lv_allocation_locked: str | None = None
    lv_autoactivation: str | None = None
    lv_when_full: str | None = None
    lv_skip_activation: str | None = None
    lv_fixed_minor: str | None = None

    # Timing and host information
    lv_time: str | None = None
    lv_time_removed: str | None = None
    lv_host: str | None = None

    # Health and status checks
    lv_health_status: str | None = None
    lv_check_needed: str | None = None
    lv_merge_failed: str | None = None
    lv_snapshot_invalid: str | None = None

    # Miscellaneous
    lv_tags: str | None = None
    lv_profile: str | None = None
    lv_lockargs: str | None = None
    lv_modules: str | None = None
    lv_historical: str | None = None
    kernel_discards: str | None = None
    copy_percent: str | None = None
    sync_percent: str | None = None

    # Device table status
    lv_live_table: str | None = None
    lv_inactive_table: str | None = None
    lv_device_open: str | None = None

    # Hierarchical relationships
    lv_parent: str | None = None
    lv_ancestors: str | None = None
    lv_full_ancestors: str | None = None
    lv_descendants: str | None = None
    lv_full_descendants: str | None = None

    # Conversion and movement
    lv_converting: str | None = None
    lv_merging: str | None = None
    move_pv: str | None = None
    move_pv_uuid: str | None = None
    convert_lv: str | None = None
    convert_lv_uuid: str | None = None

    # Mirror information
    mirror_log: str | None = None
    mirror_log_uuid: str | None = None

    # Synchronization
    lv_initial_image_sync: str | None = None
    lv_image_synced: str | None = None

    # Integrity
    raidintegritymode: str | None = None
    raidintegrityblocksize: str | None = None
    integritymismatches: str | None = None
    kernel_metadata_format: str | None = None

    # Segment information (from seg_all)
    segtype: str | None = None
    stripes: int | None = None
    data_stripes: str | None = None
    stripe_size: str | None = None
    region_size: str | None = None
    chunk_size: str | None = None
    seg_start: str | None = None
    seg_start_pe: str | None = None
    seg_size: str | None = None
    seg_size_pe: str | None = None
    seg_tags: str | None = None
    seg_pe_ranges: str | None = None
    seg_le_ranges: str | None = None
    seg_metadata_le_ranges: str | None = None
    devices: str | None = None
    metadata_devices: str | None = None
    seg_monitor: str | None = None

    # Additional segment fields
    reshape_len: str | None = None
    reshape_len_le: str | None = None
    data_copies: str | None = None
    data_offset: str | None = None
    new_data_offset: str | None = None
    parity_chunks: str | None = None
    thin_count: int | None = None
    discards: str | None = None
    cache_metadata_format: str | None = None
    cache_mode: str | None = None
    zero: str | None = None
    transaction_id: str | None = None
    thin_id: str | None = None
    cache_policy: str | None = None
    cache_settings: str | None = None
    integrity_settings: str | None = None

    # VDO segment settings
    vdo_compression: str | None = None
    vdo_deduplication: str | None = None
    vdo_minimum_io_size: str | None = None
    vdo_block_map_cache_size: str | None = None
    vdo_block_map_era_length: str | None = None
    vdo_use_sparse_index: str | None = None
    vdo_index_memory_size: str | None = None
    vdo_slab_size: str | None = None
    vdo_ack_threads: str | None = None
    vdo_bio_threads: str | None = None
    vdo_bio_rotation: str | None = None
    vdo_cpu_threads: str | None = None
    vdo_hash_zone_threads: str | None = None
    vdo_logical_threads: str | None = None
    vdo_physical_threads: str | None = None
    vdo_max_discard: str | None = None
    vdo_header_size: str | None = None
    vdo_use_metadata_hints: str | None = None
    vdo_write_policy: str | None = None

PVReport pydantic-model

Bases: ReportModel

Parsed PV data from 'pvs -o pv_all --reportformat json'.

Frozen (immutable) snapshot of one physical volume's report fields. Unknown JSON keys are silently ignored (extra='ignore').

Show JSON schema:
{
  "description": "Parsed PV data from 'pvs -o pv_all --reportformat json'.\n\nFrozen (immutable) snapshot of one physical volume's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').",
  "properties": {
    "pv_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Name"
    },
    "pv_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Uuid"
    },
    "vg_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Name"
    },
    "pv_fmt": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Fmt"
    },
    "pv_attr": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Attr"
    },
    "pv_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Size"
    },
    "pv_free": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Free"
    },
    "pv_used": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Used"
    },
    "dev_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Dev Size"
    },
    "pv_major": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Major"
    },
    "pv_minor": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Minor"
    },
    "pv_mda_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Mda Count"
    },
    "pv_mda_free": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Mda Free"
    },
    "pv_ba_start": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Ba Start"
    },
    "pv_ba_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Ba Size"
    },
    "pe_start": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pe Start"
    },
    "pv_pe_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Pe Count"
    },
    "pv_pe_alloc_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Pe Alloc Count"
    },
    "pv_tags": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Tags"
    },
    "pv_allocatable": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Allocatable"
    },
    "pv_exported": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Exported"
    },
    "pv_missing": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Missing"
    },
    "pv_in_use": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv In Use"
    },
    "pv_duplicate": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Duplicate"
    }
  },
  "title": "PVReport",
  "type": "object"
}

Fields:

  • pv_name (str | None)
  • pv_uuid (str | None)
  • vg_name (str | None)
  • pv_fmt (str | None)
  • pv_attr (str | None)
  • pv_size (str | None)
  • pv_free (str | None)
  • pv_used (str | None)
  • dev_size (str | None)
  • pv_major (str | None)
  • pv_minor (str | None)
  • pv_mda_count (str | None)
  • pv_mda_free (str | None)
  • pv_ba_start (str | None)
  • pv_ba_size (str | None)
  • pe_start (str | None)
  • pv_pe_count (str | None)
  • pv_pe_alloc_count (str | None)
  • pv_tags (str | None)
  • pv_allocatable (str | None)
  • pv_exported (str | None)
  • pv_missing (str | None)
  • pv_in_use (str | None)
  • pv_duplicate (str | None)
Source code in sts_libs/src/sts/lvm/reports.py
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
class PVReport(ReportModel):
    """Parsed PV data from 'pvs -o pv_all --reportformat json'.

    Frozen (immutable) snapshot of one physical volume's report fields.
    Unknown JSON keys are silently ignored (extra='ignore').
    """

    pv_name: str | None = None
    pv_uuid: str | None = None
    vg_name: str | None = None
    pv_fmt: str | None = None
    pv_attr: str | None = None
    pv_size: str | None = None
    pv_free: str | None = None
    pv_used: str | None = None
    dev_size: str | None = None
    pv_major: str | None = None
    pv_minor: str | None = None
    pv_mda_count: str | None = None
    pv_mda_free: str | None = None
    pv_ba_start: str | None = None
    pv_ba_size: str | None = None
    pe_start: str | None = None
    pv_pe_count: str | None = None
    pv_pe_alloc_count: str | None = None
    pv_tags: str | None = None
    pv_allocatable: str | None = None
    pv_exported: str | None = None
    pv_missing: str | None = None
    pv_in_use: str | None = None
    pv_duplicate: str | None = None

VGReport pydantic-model

Bases: ReportModel

Parsed VG data from 'vgs -o vg_all --reportformat json'.

Frozen (immutable) snapshot of one volume group's report fields. Unknown JSON keys are silently ignored (extra='ignore').

Show JSON schema:
{
  "description": "Parsed VG data from 'vgs -o vg_all --reportformat json'.\n\nFrozen (immutable) snapshot of one volume group's report fields.\nUnknown JSON keys are silently ignored (extra='ignore').",
  "properties": {
    "vg_name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Name"
    },
    "vg_uuid": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Uuid"
    },
    "vg_fmt": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Fmt"
    },
    "vg_attr": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Attr"
    },
    "vg_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Size"
    },
    "vg_free": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Free"
    },
    "vg_extent_size": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Extent Size"
    },
    "vg_extent_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Extent Count"
    },
    "vg_free_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Free Count"
    },
    "pv_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Pv Count"
    },
    "lv_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lv Count"
    },
    "snap_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Snap Count"
    },
    "vg_seqno": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Seqno"
    },
    "vg_tags": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Tags"
    },
    "vg_mda_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Mda Count"
    },
    "vg_mda_free": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Mda Free"
    },
    "max_lv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Max Lv"
    },
    "max_pv": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Max Pv"
    },
    "vg_permissions": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Permissions"
    },
    "vg_allocation_policy": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Allocation Policy"
    },
    "vg_clustered": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Clustered"
    },
    "vg_exported": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Exported"
    },
    "vg_partial": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Partial"
    },
    "vg_missing_pv_count": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vg Missing Pv Count"
    }
  },
  "title": "VGReport",
  "type": "object"
}

Fields:

  • vg_name (str | None)
  • vg_uuid (str | None)
  • vg_fmt (str | None)
  • vg_attr (str | None)
  • vg_size (str | None)
  • vg_free (str | None)
  • vg_extent_size (str | None)
  • vg_extent_count (str | None)
  • vg_free_count (str | None)
  • pv_count (str | None)
  • lv_count (str | None)
  • snap_count (str | None)
  • vg_seqno (str | None)
  • vg_tags (str | None)
  • vg_mda_count (str | None)
  • vg_mda_free (str | None)
  • max_lv (str | None)
  • max_pv (str | None)
  • vg_permissions (str | None)
  • vg_allocation_policy (str | None)
  • vg_clustered (str | None)
  • vg_exported (str | None)
  • vg_partial (str | None)
  • vg_missing_pv_count (str | None)
Source code in sts_libs/src/sts/lvm/reports.py
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
class VGReport(ReportModel):
    """Parsed VG data from 'vgs -o vg_all --reportformat json'.

    Frozen (immutable) snapshot of one volume group's report fields.
    Unknown JSON keys are silently ignored (extra='ignore').
    """

    vg_name: str | None = None
    vg_uuid: str | None = None
    vg_fmt: str | None = None
    vg_attr: str | None = None
    vg_size: str | None = None
    vg_free: str | None = None
    vg_extent_size: str | None = None
    vg_extent_count: str | None = None
    vg_free_count: str | None = None
    pv_count: str | None = None
    lv_count: str | None = None
    snap_count: str | None = None
    vg_seqno: str | None = None
    vg_tags: str | None = None
    vg_mda_count: str | None = None
    vg_mda_free: str | None = None
    max_lv: str | None = None
    max_pv: str | None = None
    vg_permissions: str | None = None
    vg_allocation_policy: str | None = None
    vg_clustered: str | None = None
    vg_exported: str | None = None
    vg_partial: str | None = None
    vg_missing_pv_count: str | None = None

fetch_all_lv_reports(vg=None)

Fetch reports for all logical volumes.

Uses lvs -a which includes hidden/internal LVs (e.g., [pool]_tdata, [pool]_tmeta, thin pool metadata volumes). Without -a, only user-visible LVs are returned.

Source code in sts_libs/src/sts/lvm/reports.py
320
321
322
323
324
325
326
327
328
329
330
331
332
333
def fetch_all_lv_reports(vg: str | None = None) -> list[LVReport]:
    """Fetch reports for all logical volumes.

    Uses ``lvs -a`` which includes hidden/internal LVs (e.g., ``[pool]_tdata``,
    ``[pool]_tmeta``, thin pool metadata volumes). Without ``-a``, only user-visible
    LVs are returned.
    """
    argv = ['lvs', '-a', '-o', 'lv_all,vg_name,seg_all', '--reportformat', 'json']
    if vg:
        argv.append(vg)
    result = run_argv(argv)
    if result.failed or not result.stdout:
        return []
    return _parse_all_lvm_reports(result.stdout, 'lv', LVReport)

fetch_all_pv_reports()

Fetch reports for all physical volumes.

Source code in sts_libs/src/sts/lvm/reports.py
378
379
380
381
382
383
def fetch_all_pv_reports() -> list[PVReport]:
    """Fetch reports for all physical volumes."""
    result = run_argv(['pvs', '-o', 'pv_all', '--reportformat', 'json'])
    if result.failed or not result.stdout:
        return []
    return _parse_all_lvm_reports(result.stdout, 'pv', PVReport)

fetch_all_vg_reports()

Fetch reports for all volume groups.

Source code in sts_libs/src/sts/lvm/reports.py
428
429
430
431
432
433
def fetch_all_vg_reports() -> list[VGReport]:
    """Fetch reports for all volume groups."""
    result = run_argv(['vgs', '-o', 'vg_all', '--reportformat', 'json'])
    if result.failed or not result.stdout:
        return []
    return _parse_all_lvm_reports(result.stdout, 'vg', VGReport)

fetch_lv_report(name, vg)

Fetch LV report for a single logical volume.

Source code in sts_libs/src/sts/lvm/reports.py
311
312
313
314
315
316
317
def fetch_lv_report(name: str, vg: str) -> LVReport | None:
    """Fetch LV report for a single logical volume."""
    result = run_argv(['lvs', '-a', '-o', 'lv_all,seg_all', f'{vg}/{name}', '--reportformat', 'json'])
    if result.failed or not result.stdout:
        logger.error(f'Failed to get LV report data for {vg}/{name}')
        return None
    return _parse_lvm_report(result.stdout, 'lv', LVReport)

fetch_pv_report(path)

Fetch PV report for a single physical volume.

Source code in sts_libs/src/sts/lvm/reports.py
369
370
371
372
373
374
375
def fetch_pv_report(path: str) -> PVReport | None:
    """Fetch PV report for a single physical volume."""
    result = run_argv(['pvs', '-o', 'pv_all', path, '--reportformat', 'json'])
    if result.failed or not result.stdout:
        logger.error(f'Failed to get PV report data for {path}')
        return None
    return _parse_lvm_report(result.stdout, 'pv', PVReport)

fetch_vg_report(name)

Fetch VG report for a single volume group.

Source code in sts_libs/src/sts/lvm/reports.py
419
420
421
422
423
424
425
def fetch_vg_report(name: str) -> VGReport | None:
    """Fetch VG report for a single volume group."""
    result = run_argv(['vgs', '-o', 'vg_all', name, '--reportformat', 'json'])
    if result.failed or not result.stdout:
        logger.error(f'Failed to get VG report data for {name}')
        return None
    return _parse_lvm_report(result.stdout, 'vg', VGReport)

sts.lvm.options

Typed CLI options for LVM commands.

Each TypedDict enumerates the options a given lvm2 subcommand actually accepts, keyed exactly as the CLI flag (underscores become hyphens via build_options()). Methods on PhysicalVolume/VolumeGroup/LogicalVolume/ ThinPool accept these via PEP 692 Unpack[...], so lv.create(size='1G') keeps working unchanged while basedpyright now rejects typos and unknown keys statically.

LvChangeOptions

Bases: TypedDict

Options for lvchange.

Source code in sts_libs/src/sts/lvm/options.py
75
76
77
78
79
80
class LvChangeOptions(TypedDict, total=False):
    """Options for `lvchange`."""

    discards: Discards
    permission: Literal['r', 'rw']
    vdosettings: str

LvConvertOptions

Bases: TypedDict

Options for lvconvert.

Source code in sts_libs/src/sts/lvm/options.py
105
106
107
108
109
110
111
112
113
114
115
116
117
class LvConvertOptions(TypedDict, total=False):
    """Options for `lvconvert`."""

    type: str
    thinpool: str
    originname: str
    poolmetadata: str
    poolmetadatasize: str
    chunksize: str
    zero: str
    discards: Discards
    mirrors: str
    readahead: str

LvConvertOriginnameOptions

Bases: TypedDict

Options for lvconvert --originname.

Excludes type/thinpool/originname, which convert_originname() takes as explicit parameters instead (PEP 692 forbids overlap between a TypedDict unpacked via **options and named parameters sharing its keys).

Source code in sts_libs/src/sts/lvm/options.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
class LvConvertOriginnameOptions(TypedDict, total=False):
    """Options for `lvconvert --originname`.

    Excludes type/thinpool/originname, which `convert_originname()` takes as
    explicit parameters instead (PEP 692 forbids overlap between a TypedDict
    unpacked via `**options` and named parameters sharing its keys).
    """

    poolmetadata: str
    poolmetadatasize: str
    chunksize: str
    zero: str
    discards: Discards
    mirrors: str
    readahead: str

LvCreateOptions

Bases: TypedDict

Options for lvcreate.

Source code in sts_libs/src/sts/lvm/options.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class LvCreateOptions(TypedDict, total=False):
    """Options for `lvcreate`."""

    size: str
    extents: str
    virtualsize: str
    type: LvType
    thinpool: str
    vdopool: str
    poolmetadata: str
    poolmetadatasize: str
    poolmetadataspare: str
    chunksize: str
    zero: str
    discards: Discards
    stripes: str
    stripesize: str
    mirrors: str
    vdosettings: str

LvExtendOptions

Bases: TypedDict

Options for lvextend.

Source code in sts_libs/src/sts/lvm/options.py
83
84
85
86
87
class LvExtendOptions(TypedDict, total=False):
    """Options for `lvextend`."""

    size: str
    extents: str

LvReduceOptions

Bases: TypedDict

Options for lvreduce.

Source code in sts_libs/src/sts/lvm/options.py
90
91
92
93
94
class LvReduceOptions(TypedDict, total=False):
    """Options for `lvreduce`."""

    size: str
    extents: str

LvRemoveOptions

Bases: TypedDict

Options for lvremove.

Source code in sts_libs/src/sts/lvm/options.py
71
72
class LvRemoveOptions(TypedDict, total=False):
    """Options for `lvremove`."""

LvResizeOptions

Bases: TypedDict

Options for lvresize.

Source code in sts_libs/src/sts/lvm/options.py
 97
 98
 99
100
101
102
class LvResizeOptions(TypedDict, total=False):
    """Options for `lvresize`."""

    size: str
    extents: str
    poolmetadatasize: str

LvsOptions

Bases: TypedDict

Options for lvs.

Source code in sts_libs/src/sts/lvm/options.py
137
138
139
140
141
142
143
class LvsOptions(TypedDict, total=False):
    """Options for `lvs`."""

    o: str
    O: str  # noqa: E741 - matches the lvs -O flag name
    S: str
    noheadings: bool

PvCreateOptions

Bases: TypedDict

Options for pvcreate.

Source code in sts_libs/src/sts/lvm/options.py
22
23
24
25
26
27
class PvCreateOptions(TypedDict, total=False):
    """Options for `pvcreate`."""

    dataalignment: str
    metadatasize: str
    metadatacopies: str

PvRemoveOptions

Bases: TypedDict

Options for pvremove.

Source code in sts_libs/src/sts/lvm/options.py
30
31
class PvRemoveOptions(TypedDict, total=False):
    """Options for `pvremove`."""

VgChangeOptions

Bases: TypedDict

Options for vgchange (activate/deactivate).

Source code in sts_libs/src/sts/lvm/options.py
46
47
class VgChangeOptions(TypedDict, total=False):
    """Options for `vgchange` (activate/deactivate)."""

VgCreateOptions

Bases: TypedDict

Options for vgcreate.

Source code in sts_libs/src/sts/lvm/options.py
34
35
36
37
38
39
class VgCreateOptions(TypedDict, total=False):
    """Options for `vgcreate`."""

    physicalextentsize: str
    maxlogicalvolumes: str
    maxphysicalvolumes: str

VgRemoveOptions

Bases: TypedDict

Options for vgremove.

Source code in sts_libs/src/sts/lvm/options.py
42
43
class VgRemoveOptions(TypedDict, total=False):
    """Options for `vgremove`."""

sts.lvm.lvconf

Read and update key-value settings in /etc/lvm/lvm.conf.

Handles both commented-out (default) and uncommented (active) values.

LvmConfig pydantic-model

Bases: StsBaseModel

LVM configuration manager.

Example
config = LvmConfig()
threshold = config.get('thin_pool_autoextend_threshold')
config.set('thin_pool_autoextend_threshold', '80')
Show JSON schema:
{
  "additionalProperties": false,
  "description": "LVM configuration manager.\n\nExample:\n    ```python\n    config = LvmConfig()\n    threshold = config.get('thin_pool_autoextend_threshold')\n    config.set('thin_pool_autoextend_threshold', '80')\n    ```",
  "properties": {
    "config_path": {
      "default": "/etc/lvm/lvm.conf",
      "format": "path",
      "title": "Config Path",
      "type": "string"
    }
  },
  "title": "LvmConfig",
  "type": "object"
}

Fields:

  • config_path (Path)
Source code in sts_libs/src/sts/lvm/lvconf.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
class LvmConfig(StsBaseModel):
    """LVM configuration manager.

    Example:
        ```python
        config = LvmConfig()
        threshold = config.get('thin_pool_autoextend_threshold')
        config.set('thin_pool_autoextend_threshold', '80')
        ```
    """

    config_path: Path = Path('/etc/lvm/lvm.conf')

    # Common thin provisioning configuration keys
    THIN_POOL_AUTOEXTEND_THRESHOLD: ClassVar[str] = 'thin_pool_autoextend_threshold'
    THIN_POOL_AUTOEXTEND_PERCENT: ClassVar[str] = 'thin_pool_autoextend_percent'
    THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS: ClassVar[str] = 'thin_pool_metadata_require_separate_pvs'

    def exists(self) -> bool:
        """Check if the configuration file exists."""
        return self.config_path.exists()

    def get(self, key: str) -> str | None:
        """Get configuration value from lvm.conf.

        Handles both commented (default) and uncommented (active) values.
        If both exist, returns the uncommented (active) value.
        """
        if not self.exists():
            logger.warning(f'LVM config file {self.config_path} not found')
            return None

        # Pattern to match both commented and uncommented key = value
        # Captures: (optional #) (whitespace) key (whitespace) = (whitespace) value
        # The value pattern handles the last occurrence of "key = value" format
        search_regex = re.compile(rf'^\s*#?\s*{re.escape(key)}\s*=\s*(\S+)')

        uncommented_value = None
        commented_value = None

        try:
            for line in self.config_path.read_text().splitlines():
                match = search_regex.match(line)
                if match:
                    value = match.group(1)
                    # Check if this is a commented line
                    if line.strip().startswith('#'):
                        commented_value = value
                    else:
                        uncommented_value = value
        except OSError:
            logger.exception(f'Failed to read LVM config file {self.config_path}')
            return None

        # Prefer uncommented (active) value over commented (default) value
        return uncommented_value if uncommented_value is not None else commented_value

    def set(self, key: str, value: str) -> bool:
        """Update a configuration value in lvm.conf.

        If the key is commented out, it will be uncommented.
        Preserves the original indentation.
        """
        if not self.exists():
            logger.error(f'LVM config file {self.config_path} not found')
            return False

        # Pattern to match both commented and uncommented key = value
        # Captures leading whitespace and optional comment marker
        search_regex = re.compile(rf'^(\s*)(#?\s*){re.escape(key)}(\s*)=(\s*)\S*')

        try:
            lines = self.config_path.read_text().splitlines()
            updated_lines: list[str] = []
            found = False

            for line in lines:
                match = search_regex.match(line)
                if match and not found:
                    # Get the leading whitespace (indentation)
                    indent = match.group(1)
                    # Create new line without comment marker
                    updated_lines.append(f'{indent}{key} = {value}')
                    found = True
                else:
                    updated_lines.append(line)

            if not found:
                logger.warning(f'Configuration key {key} not found in {self.config_path}')
                return False

            self.config_path.write_text('\n'.join(updated_lines) + '\n')

        except OSError:
            logger.exception(f'Failed to update LVM config file {self.config_path}')
            return False

        return True

    def set_multiple(self, settings: dict[str, str]) -> bool:
        """Update multiple configuration values in a single file pass.

        If keys are commented out, they will be uncommented.
        """
        if not self.exists():
            logger.error(f'LVM config file {self.config_path} not found')
            return False

        try:
            lines = self.config_path.read_text().splitlines()
            updated_lines: list[str] = []
            keys_found: set[str] = set()

            for line in lines:
                updated_line = line
                for key, value in settings.items():
                    if key in keys_found:
                        continue
                    # Pattern to match both commented and uncommented key = value
                    search_regex = re.compile(rf'^(\s*)(#?\s*){re.escape(key)}(\s*)=(\s*)\S*')
                    match = search_regex.match(line)
                    if match:
                        # Get the leading whitespace (indentation)
                        indent = match.group(1)
                        # Create new line without comment marker
                        updated_line = f'{indent}{key} = {value}'
                        keys_found.add(key)
                        break
                updated_lines.append(updated_line)

            # Check if all keys were found
            missing_keys = set(settings.keys()) - keys_found
            if missing_keys:
                logger.warning(f'Configuration keys not found: {missing_keys}')
                return False

            self.config_path.write_text('\n'.join(updated_lines) + '\n')

        except OSError:
            logger.exception(f'Failed to update LVM config file {self.config_path}')
            return False

        return True

    def get_thin_pool_autoextend_threshold(self) -> str | None:
        """Get thin pool autoextend threshold."""
        return self.get(self.THIN_POOL_AUTOEXTEND_THRESHOLD)

    def set_thin_pool_autoextend_threshold(self, value: str) -> bool:
        """Set thin pool autoextend threshold."""
        return self.set(self.THIN_POOL_AUTOEXTEND_THRESHOLD, value)

    def get_thin_pool_autoextend_percent(self) -> str | None:
        """Get thin pool autoextend percent."""
        return self.get(self.THIN_POOL_AUTOEXTEND_PERCENT)

    def set_thin_pool_autoextend_percent(self, value: str) -> bool:
        """Set thin pool autoextend percent."""
        return self.set(self.THIN_POOL_AUTOEXTEND_PERCENT, value)

    def get_thin_pool_metadata_require_separate_pvs(self) -> str | None:
        """Get thin pool metadata require separate PVs setting."""
        return self.get(self.THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS)

    def set_thin_pool_metadata_require_separate_pvs(self, value: str) -> bool:
        """Set thin pool metadata require separate PVs setting."""
        return self.set(self.THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, value)

exists()

Check if the configuration file exists.

Source code in sts_libs/src/sts/lvm/lvconf.py
39
40
41
def exists(self) -> bool:
    """Check if the configuration file exists."""
    return self.config_path.exists()

get(key)

Get configuration value from lvm.conf.

Handles both commented (default) and uncommented (active) values. If both exist, returns the uncommented (active) value.

Source code in sts_libs/src/sts/lvm/lvconf.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def get(self, key: str) -> str | None:
    """Get configuration value from lvm.conf.

    Handles both commented (default) and uncommented (active) values.
    If both exist, returns the uncommented (active) value.
    """
    if not self.exists():
        logger.warning(f'LVM config file {self.config_path} not found')
        return None

    # Pattern to match both commented and uncommented key = value
    # Captures: (optional #) (whitespace) key (whitespace) = (whitespace) value
    # The value pattern handles the last occurrence of "key = value" format
    search_regex = re.compile(rf'^\s*#?\s*{re.escape(key)}\s*=\s*(\S+)')

    uncommented_value = None
    commented_value = None

    try:
        for line in self.config_path.read_text().splitlines():
            match = search_regex.match(line)
            if match:
                value = match.group(1)
                # Check if this is a commented line
                if line.strip().startswith('#'):
                    commented_value = value
                else:
                    uncommented_value = value
    except OSError:
        logger.exception(f'Failed to read LVM config file {self.config_path}')
        return None

    # Prefer uncommented (active) value over commented (default) value
    return uncommented_value if uncommented_value is not None else commented_value

get_thin_pool_autoextend_percent()

Get thin pool autoextend percent.

Source code in sts_libs/src/sts/lvm/lvconf.py
173
174
175
def get_thin_pool_autoextend_percent(self) -> str | None:
    """Get thin pool autoextend percent."""
    return self.get(self.THIN_POOL_AUTOEXTEND_PERCENT)

get_thin_pool_autoextend_threshold()

Get thin pool autoextend threshold.

Source code in sts_libs/src/sts/lvm/lvconf.py
165
166
167
def get_thin_pool_autoextend_threshold(self) -> str | None:
    """Get thin pool autoextend threshold."""
    return self.get(self.THIN_POOL_AUTOEXTEND_THRESHOLD)

get_thin_pool_metadata_require_separate_pvs()

Get thin pool metadata require separate PVs setting.

Source code in sts_libs/src/sts/lvm/lvconf.py
181
182
183
def get_thin_pool_metadata_require_separate_pvs(self) -> str | None:
    """Get thin pool metadata require separate PVs setting."""
    return self.get(self.THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS)

set(key, value)

Update a configuration value in lvm.conf.

If the key is commented out, it will be uncommented. Preserves the original indentation.

Source code in sts_libs/src/sts/lvm/lvconf.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def set(self, key: str, value: str) -> bool:
    """Update a configuration value in lvm.conf.

    If the key is commented out, it will be uncommented.
    Preserves the original indentation.
    """
    if not self.exists():
        logger.error(f'LVM config file {self.config_path} not found')
        return False

    # Pattern to match both commented and uncommented key = value
    # Captures leading whitespace and optional comment marker
    search_regex = re.compile(rf'^(\s*)(#?\s*){re.escape(key)}(\s*)=(\s*)\S*')

    try:
        lines = self.config_path.read_text().splitlines()
        updated_lines: list[str] = []
        found = False

        for line in lines:
            match = search_regex.match(line)
            if match and not found:
                # Get the leading whitespace (indentation)
                indent = match.group(1)
                # Create new line without comment marker
                updated_lines.append(f'{indent}{key} = {value}')
                found = True
            else:
                updated_lines.append(line)

        if not found:
            logger.warning(f'Configuration key {key} not found in {self.config_path}')
            return False

        self.config_path.write_text('\n'.join(updated_lines) + '\n')

    except OSError:
        logger.exception(f'Failed to update LVM config file {self.config_path}')
        return False

    return True

set_multiple(settings)

Update multiple configuration values in a single file pass.

If keys are commented out, they will be uncommented.

Source code in sts_libs/src/sts/lvm/lvconf.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
def set_multiple(self, settings: dict[str, str]) -> bool:
    """Update multiple configuration values in a single file pass.

    If keys are commented out, they will be uncommented.
    """
    if not self.exists():
        logger.error(f'LVM config file {self.config_path} not found')
        return False

    try:
        lines = self.config_path.read_text().splitlines()
        updated_lines: list[str] = []
        keys_found: set[str] = set()

        for line in lines:
            updated_line = line
            for key, value in settings.items():
                if key in keys_found:
                    continue
                # Pattern to match both commented and uncommented key = value
                search_regex = re.compile(rf'^(\s*)(#?\s*){re.escape(key)}(\s*)=(\s*)\S*')
                match = search_regex.match(line)
                if match:
                    # Get the leading whitespace (indentation)
                    indent = match.group(1)
                    # Create new line without comment marker
                    updated_line = f'{indent}{key} = {value}'
                    keys_found.add(key)
                    break
            updated_lines.append(updated_line)

        # Check if all keys were found
        missing_keys = set(settings.keys()) - keys_found
        if missing_keys:
            logger.warning(f'Configuration keys not found: {missing_keys}')
            return False

        self.config_path.write_text('\n'.join(updated_lines) + '\n')

    except OSError:
        logger.exception(f'Failed to update LVM config file {self.config_path}')
        return False

    return True

set_thin_pool_autoextend_percent(value)

Set thin pool autoextend percent.

Source code in sts_libs/src/sts/lvm/lvconf.py
177
178
179
def set_thin_pool_autoextend_percent(self, value: str) -> bool:
    """Set thin pool autoextend percent."""
    return self.set(self.THIN_POOL_AUTOEXTEND_PERCENT, value)

set_thin_pool_autoextend_threshold(value)

Set thin pool autoextend threshold.

Source code in sts_libs/src/sts/lvm/lvconf.py
169
170
171
def set_thin_pool_autoextend_threshold(self, value: str) -> bool:
    """Set thin pool autoextend threshold."""
    return self.set(self.THIN_POOL_AUTOEXTEND_THRESHOLD, value)

set_thin_pool_metadata_require_separate_pvs(value)

Set thin pool metadata require separate PVs setting.

Source code in sts_libs/src/sts/lvm/lvconf.py
185
186
187
def set_thin_pool_metadata_require_separate_pvs(self, value: str) -> bool:
    """Set thin pool metadata require separate PVs setting."""
    return self.set(self.THIN_POOL_METADATA_REQUIRE_SEPARATE_PVS, value)