DEVELOPER DOCS

Storage operations,
without guesswork.

Run one Parto binary to inspect the real VM storage path and its health, produce automation-ready JSON, review a dry run, and safely grow mounted XFS.

01 · START HERE

Install one executable

Choose the Parto executable for your operating system and CPU architecture, put it where you keep command-line tools, and run it.

LINUX
chmod +x parto_linux_amd64
sudo mv parto_linux_amd64 /usr/local/bin/parto
parto --version
MACOS · APPLE SILICON
chmod +x parto_darwin_arm64
sudo mv parto_darwin_arm64 /usr/local/bin/parto
parto --version
WINDOWS · POWERSHELL
New-Item -ItemType Directory -Force "$HOME\bin"
Move-Item .\parto_windows_amd64.exe "$HOME\bin\parto.exe"
& "$HOME\bin\parto.exe" --version

Use the arm64 file on ARM64 systems and amd64 on x86-64. On Windows, add $HOME\bin to PATH only if you want to run parto.exe from any directory.

Safe first run

Start with read-only inspection. Then run a size-specific dry run. Remove --dry-run only after both outputs look correct.

RECOMMENDED SEQUENCE
parto inspect [options]
parto grow [options] --dry-run
parto grow [options]

02 · READY CHECK

What Parto needs

Parto connects three parts of the operation: the machine running the command, the OpenStack control plane, and the target VM. Have each one ready before the first inspection.

01OPERATOR

Run the Parto binary

A Linux, macOS, or Windows Parto executable matching the CPU architecture, OpenStack API access, and SSH access directly or through PAS.

02CLOUD

Authenticate to OpenStack

Permission to read servers and attachments, read volumes, create and attach a volume, or extend an existing volume.

03TARGET

Reach the target VM

A mounted non-root XFS data filesystem, sudo access, and the required Linux storage utilities including df.

OPTIONAL

Centralize environments

Add PostgreSQL only when you use --environment. Standalone --cloud and OS_* workflows stay database-free.

TARGET UTILITIES

Common packages include util-linux, parted, lvm2,xfsprogs, and cloud-guest-utils. growpart is only required for partition-backed XFS; smartmontools is optional for best-effort SMART inspection.

03 · CONNECT

Configure OpenStack

Use --cloud to select a profile explicitly. When it is omitted, Parto checks OS_CLOUD, selects the only profile in the first discovered clouds.yaml, and uses OS_* credentials when no config file exists.

A cloud is a local profile

--cloud example-cloud selects the example-cloud key under clouds:. It is not an OpenStack project name. The selected profile supplies authentication, project scope, region, and TLS settings.

Automatic profile selection

A single profile is selected automatically. If clouds.yaml contains multiple profiles, Parto stops and asks for --cloud instead of guessing.

~/.config/openstack/clouds.yaml
clouds:
  example-cloud:
    auth_type: password
    auth:
      auth_url: https://identity.example.com/v3
      username: example-user
      project_name: example-project
      user_domain_name: Default
      project_domain_name: Default
    region_name: RegionOne
    interface: public
    identity_api_version: 3
    verify: true
~/.config/openstack/secure.yaml
clouds:
  example-cloud:
    auth:
      password: replace-with-your-openstack-password
INSTALL AND VERIFY
chmod 600 ~/.config/openstack/clouds.yaml ~/.config/openstack/secure.yaml
openstack --os-cloud example-cloud token issue
openstack --os-cloud example-cloud server show my-vm
openstack --os-cloud example-cloud server volume list my-vm
Keep TLS verification enabled

For a private CA, add cacert: /path/to/company-ca.pem. Do not solve certificate errors with verify: false.

Parto requests Cinder API microversion 3.42 for online extension of attached volumes. The cloud policy and storage backend must also allow it.

04 · MANAGED CONNECTIONS

Import encrypted OpenStack environments

Managed environments let Parto resolve an OpenStack target from PostgreSQL instead of reading a local profile on every run. An environment binds the source cloud profile, immutable project ID, project metadata, region, and encrypted credential payload.

SelectorWhat it selectsCredential source
--cloud example-cloudA profile named example-cloudLocal clouds.yaml, secure.yaml, or OS_*
--environment production-searchA Parto environment recordEncrypted PostgreSQL payload, decrypted only in memory

--cloud and --environment are mutually exclusive.

Start PostgreSQL for local development

POSTGRESQL · DOCKER
docker volume create parto-postgres-data

docker run -d \
  --name parto-postgres \
  --restart unless-stopped \
  -e POSTGRES_USER=parto \
  -e POSTGRES_PASSWORD=parto-local-password \
  -e POSTGRES_DB=parto \
  -v parto-postgres-data:/var/lib/postgresql/data \
  -p 127.0.0.1:55432:5432 \
  postgres:17-alpine
CONFIGURE THIS SHELL
export PARTO_DATABASE_URL='postgres://parto:parto-local-password@127.0.0.1:55432/parto?sslmode=disable'
openssl rand -base64 32  # Generate once and save the value.
export PARTO_MASTER_KEY='paste-the-saved-value-here'

Parto creates its environment table on first use. Keep the same master key for every later run; losing or replacing it makes existing credential records unreadable.

Import one project-scoped profile

APPLICATION CREDENTIAL · RECOMMENDED
parto environment import \
  --file ~/.config/openstack/clouds.yaml \
  --cloud example-cloud \
  --name-prefix production-search

parto environment list

Here example-cloud is the profile name in the YAML file, while production-search becomes the Parto environment name. OpenStack application credentials are project-scoped, so import one profile for each project.

Discover projects available to a user

USERNAME/PASSWORD PROFILE
parto environment import \
  --file ~/.config/openstack/clouds.yaml \
  --cloud company \
  --discover-projects \
  --name-prefix production

Project discovery is explicit and works only with username/password credentials that can be re-scoped. Parto imports every enabled accessible project using its immutable project ID. It does not use project names as OpenStack identity.

Credentials stay encrypted

Parto uses AES-256-GCM before writing credential payloads to PostgreSQL, never returns them from environment list, and never writes a temporary managed clouds.yaml. Keep PARTO_MASTER_KEY outside the database.

USE THE IMPORTED ENVIRONMENT
parto inspect \
  --environment production-search \
  --vm-name my-vm \
  --mountpoint /srv/data \
  --ssh-user ubuntu \
  --ssh-key ~/.ssh/id_rsa

05 · READ ONLY

Inspect before changing anything

inspect discovers eligible data targets and runs preflight checks. It does not accept --size, run mutations, ask for approvals, or write an operation journal.

INSPECT EVERY ELIGIBLE TARGET
parto inspect \
  --cloud example-cloud \
  --vm-name my-vm \
  --ssh-user ubuntu \
  --ssh-key ~/.ssh/id_rsa
INSPECT ONE MOUNTPOINT
parto inspect \
  --cloud example-cloud \
  --vm-name my-vm \
  --mountpoint /srv/data \
  --ssh-user ubuntu \
  --ssh-key ~/.ssh/id_rsa

06 · OBSERVE AND INTEGRATE

Filesystem health and JSON output

Every inspected target includes filesystem capacity and inode pressure. Parto also follows the target to its physical disks and reads SMART health when the VM exposes it.

SignalReported dataBehavior
FilesystemTotal, used, available bytes, and used percentagehealthy below 80%, warning at 80%, critical at 90%
InodesTotal, used, available count, and used percentageUses the same informational thresholds
SMARTPass/fail, model, serial, temperature, and power-on hours when availableunavailable is non-fatal on virtual disks
INSPECT AS JSON
parto inspect \
  --cloud example-cloud \
  --vm-name my-vm \
  --mountpoint /srv/data \
  --ssh-user ubuntu \
  --ssh-key ~/.ssh/id_rsa \
  --json | jq '.targets[].health'
Automation-safe output

--json writes one JSON document to stdout. Prompts and operational diagnostics use stderr. Structured errors preserve the normal Parto exit codes.

SMART is best-effort. Parto uses smartctl when installed, supports older text-only output, and reports each underlying LVM disk separately. Missing or hidden SMART data never makes inspection fail.

07 · PLAN, THEN APPLY

Dry-run and grow

A dry run performs real read-only discovery and prints the planned OpenStack and guest commands without applying them.

XFS ON A DISK OR PARTITION
parto grow \
  --cloud example-cloud \
  --vm-name my-vm \
  --mountpoint /srv/data \
  --size 110 \
  --ssh-user ubuntu \
  --ssh-key ~/.ssh/id_rsa \
  --dry-run

Here 110 is the new total Cinder volume size in GB.

XFS ON LVM
parto grow \
  --cloud example-cloud \
  --vm-name my-vm \
  --mountpoint /data \
  --size 50 \
  --ssh-user ubuntu \
  --ssh-key ~/.ssh/id_rsa \
  --dry-run

Here 50 is the size of a new Cinder volume added to the volume group.

Real run

Remove --dry-run after reviewing the plan. Parto asks for initial approval and confirms every mutating remote command.

08 · PICK THE RIGHT PATH

Filesystem and target selection

XFS is the filesystem. LVM, a partition, or a whole disk is the storage layout underneath it. The recommended selector is always the mounted filesystem: --mountpoint /data.

  • Recommended: --mountpoint /data works for all supported layouts.
  • LVM alternative: --lv-name data-lv accepts the plain LV name.
  • Auto-detect: omit both only when exactly one eligible non-root target exists.

The root filesystem and protected operating-system or runtime trees are never eligible. A target sharing the physical root disk is also rejected.

Protected system paths
//bin/boot/dev/efi/etc/lib/lib64/proc/root/run/sbin/snap/sys/usr/var/lib/snapd/snap/var/lock/var/run

Every descendant of these paths is protected too.

Data locations such as /data, /home, /mnt/storage, /opt/data, /srv, /tmp, and /var remain eligible when every other safety check passes.

09 · IMPORTANT

Understand --size

The meaning changes with the detected storage layout.

XFS placementActionMeaning of --size
On LVMAdd a new Cinder volumeNew volume size in GB
On a partitionGrow volume and partitionNew total volume size in GB
On a whole diskGrow existing volumeNew total volume size in GB
50 GB means two different things

On LVM, --size 50 adds a new 50 GB disk. For an existing 50 GB whole-disk volume that needs 20 GB more, use --size 70.

10 · ACCESS

SSH, sudo, and PAS

Direct SSH with a key

DIRECT SSH
parto inspect \
  --cloud example-cloud \
  --vm-name my-vm \
  --ssh-user ubuntu \
  --ssh-key ~/.ssh/id_rsa

Omit --ssh-key and --ssh-password to prompt for the SSH password. Add --ask-sudo-password when sudo is not passwordless.

PAS gateway

--ssh-gateway is the host you connect to. --ssh-gateway-login is the username template sent to that gateway; it must contain {target}.

PAS DRY RUN
parto grow \
  --cloud example-cloud \
  --vm-name my-vm \
  --mountpoint /srv/data \
  --size 110 \
  --ssh-gateway pas.example.com \
  --ssh-gateway-login 'centrify@{target}@user@example.com' \
  --dry-run

11 · GUARDRAILS

Safety and recovery

  • The root disk and protected OS/runtime mount trees are never touched.
  • Only mounted XFS filesystems are supported; other filesystems stop in preflight.
  • Every mutating command requires operator confirmation.
  • New guest disks are matched to exact Cinder volume IDs by serial.
  • Timeouts and ambiguous outcomes stop the workflow instead of guessing.
  • There is no automatic rollback, detach, delete, or LVM cleanup.

Operation journal

Every grow attempt that selects a target writes a private JSON record with mode 0600. It contains checkpoints and non-secret recovery context.

DEFAULT JOURNAL LOCATION
~/.local/state/parto/runs/
# or ${XDG_STATE_HOME}/parto/runs/

Ctrl-C before mutation is a normal cancellation. After mutation begins, the result may be unknown; Parto stops and prints read-only inspection commands and manual recovery guidance. With --json, the same recovery context, failed step, inspection commands, and guidance are returned as structured fields.

12 · REFERENCE

CLI reference

OptionPurpose
--vm-nameOpenStack instance name. Required for every command.
--sizeGrow only. Positive integer in GB; meaning depends on layout.
--mountpointRecommended target selector, such as /data.
--lv-nameAlternative LVM selector using a plain LV name.
--cloudExplicit profile selector. Omit to use OS_CLOUD, one automatically discovered profile, or OS_*.
--environmentManaged OpenStack environment stored in PostgreSQL. Mutually exclusive with --cloud.
--ssh-userRequired for direct SSH.
--ssh-keySSH private-key path.
--ssh-passwordNon-interactive SSH password; interactive prompt is safer.
--ask-sudo-passwordPrompt interactively for the remote sudo password.
--ssh-gatewayPAS gateway hostname.
--ssh-gateway-loginPAS username template containing {target}.
--dry-runRead the real state and print mutations without applying them.
--jsonWrite one machine-readable result document to stdout.
COMMAND HELP
parto inspect --help
parto grow --help
parto environment --help

NEED A HAND?

Talk storage with us.

Talk to an engineer