ganeti-extstorage-interface(7)

πŸ“¦
version 3.1.0~rc2 Β· 4 versions
, in debian trixie, ubuntu questing, ubuntu resolute

✨ NAME ✨

okay so bestie, this is the ganeti-extstorage-interface manual β€” version 3.1.0~rc2 β€” and it's literally the Specifications for ExtStorage providers. no cap, this is the blueprint. πŸ’–

πŸ’– DESCRIPTION πŸ’–

So the way Ganeti handles external shared storage? It's giving each external shared storage hardware type its own ExtStorage provider. periodt.

An ExtStorage provider is literally just a set of files β€” executable scripts and text files β€” chillin' inside a directory named after the provider. πŸŽ€

That directory has to be present across all nodes of a nodegroup (Ganeti does not replicate it, bestie, so you gotta handle that yourself). Only then can Ganeti actually use the provider for that nodegroup β€” that's what makes it valid.

Also, the external shared storage hardware itself needs to be accessible by every node in that nodegroup too. no pressure. πŸ™ˆ

πŸ“š REFERENCE πŸ“š

There are eight required files: create, attach, detach, remove, grow, setinfo, verify (all executables) and parameters.list (a text file). That's the whole starter pack, bestie. ✨

Then there are three optional files: open, close, and snapshot β€” all executables. They're not mandatory, but they're iconic if you implement them. πŸ’…

🌈 Common environment 🌈

Every command gets its input through environment variables. There's a common set of variables exported for all commands, and some commands get extra ones on top. Also heads up: all counts are zero-based β€” so the first one is 0, not 1. iykyk. πŸ”’

Since Ganeti version 2.5, the environment gets cleaned up before it's passed to scripts. So your scripts do not inherit the environment that the ganeti node daemon was started with. If you're depending on any non-Ganeti environment variables, you're gonna need to define or source them yourself, appropriately. that's just the rules. πŸ’…

  • VOL_NAME β€” The name of the volume. It's unique for Ganeti and Ganeti uses it to refer to a specific volume inside the external storage. Its format is UUID.ext.diskX where UUID is produced by Ganeti and is unique inside the Ganeti context. X is the number of the disk count.
  • VOL_SIZE β€” Available only to the create and grow scripts. It's the volume's size in mebibytes.
  • VOL_NEW_SIZE β€” Available only to the grow script. It declares the new size of the volume after grow (in mebibytes). To find the amount of grow, the script should calculate the number VOL_NEW_SIZE - VOL_SIZE.
  • EXTPname β€” Each ExtStorage parameter (see below) gets exported in its own variable, prefixed with EXTP_, and upper-cased. For example, a fromsnap parameter will be exported as EXTP_FROMSNAP.
  • VOL_METADATA β€” Available only to the setinfo script. A string containing metadata to be associated with the volume. Currently, Ganeti sets this value to originstname+X where X is the instance's name.
  • VOL_CNAME β€” The human-readable name of the Disk config object (optional).
  • VOL_UUID β€” The uuid of the Disk config object.
  • VOL_SNAPSHOT_NAME β€” The name of the volume's snapshot.
  • VOL_SNAPSHOT_SIZE β€” The size of the volume's snapshot.
  • VOL_OPEN_EXCLUSIVE β€” Whether the volume will be opened for exclusive access or not. This will be False (denoting shared access) during migration.

πŸŽ₯ EXECUTABLE SCRIPTS πŸŽ₯

✨ create ✨

The create command is your go-to for making a brand new volume inside the external storage. slay.

VOL_NAME is the volume's name, and it should be unique. After creation, Ganeti will refer to this volume by this name for every other action. so don't lose it.

Ganeti produces this name dynamically and makes sure it's unique inside the Ganeti context. So please don't manually provision extra volumes inside the external storage with this type of name β€” that's a one-way ticket to conflicts and possible loss of data. not the vibe. πŸ’€

The VOL_SIZE variable tells you the size of the new volume to create, in mebibytes.

If the script ends successfully, a new volume of size VOL_SIZE should exist inside the external storage β€” e.g. a lun inside a NAS appliance.

The script returns 0 on success. periodt.

✨ attach ✨

This command makes an already-created volume visible to the physical node that's gonna host the instance. How? By mapping the already-provisioned volume to a block device inside the host node. it's giving matchmaker energy. πŸ’–

The VOL_NAME variable is the volume to map.

After a successful attach, the script returns a string to its stdout β€” the full path of the block device the volume is mapped to. e.g. /dev/dummy1.

When attach returns, that path should be a valid block device on the host node. no cap.

The attach script should be idempotent if the volume is already mapped. If the requested volume is already mapped, just return to stdout the path that's already mapped to. easy.

If the storage tech also supports userspace access to volumes β€” like, say, the QEMU Hypervisor can see an RBD volume using its embedded driver for the RBD protocol β€” then the provider can return extra lines denoting the available userspace access URIs per hypervisor. The URI should be in this format: <hypervisor>:<uri>. For example, a RADOS provider should return kvm:rbd:<pool>/<volume name> on the second line of stdout, right after the local block device path (e.g. /dev/rbd1).

So if the access disk parameter is userspace for the ext disk template, the QEMU command ends up having file=<URI> in the -drive option. that's the tea. 🍡

And if the storage tech supports only userspace access to volumes, then the first line of stdout should be an empty line β€” that denotes a local block device is not available. If you return neither a block device nor a URI, Ganeti will complain. so don't do that. 😭

✨ detach ✨

This command unmaps an already-mapped volume from the host node. detach undoes everything attach did β€” by unmapping the requested volume from the block device it's mapped to. it's the breakup era. πŸ’”

VOL_NAME is the volume to unmap.

detach doesn't touch the volume itself. It just unmaps it from the host node. The volume keeps existing inside the external storage β€” it's just not accessible by that node anymore. This script returns nothing to stdout.

The detach script should be idempotent if the volume is already unmapped. If the volume isn't mapped, the script doesn't do anything at all. periodt.

The script returns 0 on success.

✨ remove ✨

This command removes an existing volume from the external storage. And bestie, it's permanent β€” the volume and all its data get deleted from inside the external storage. no take-backs. πŸ’€

VOL_NAME is the volume to remove.

The script returns 0 on success.

✨ grow ✨

This command grows an existing volume in the external storage. glow up time. ✨

VOL_NAME is the volume to grow.

VOL_SIZE is the current volume's size (in mebibytes). VOL_NEW_SIZE is the final size after the volume has been grown (in mebibytes).

The amount of grow can be easily calculated by the script, and it's:

grow_amount = VOL_NEW_SIZE - VOL_SIZE (in mebibytes)

Ganeti ensures that: VOL_NEW_SIZE > VOL_SIZE. so no shrinking, bestie.

If the script returns successfully, the volume inside the external storage will have a new size of VOL_NEW_SIZE. But heads up: this isn't immediately reflected to the instance's disk. See gnt-instance grow for more details on when the running instance becomes aware of its grown disk. patience, bestie. 🧘

The script returns 0 on success.

✨ setinfo ✨

This script adds metadata to an existing volume. It's helpful when you need to keep an external, Ganeti-independent mapping between instances and volumes β€” primarily for recovery reasons. This is provider specific, and the provider's author chooses whether and how to implement it. If you don't wanna implement this feature, you can literally just exit with 0 β€” it won't harm the overall functionality of the provider. no stress. πŸ’…

The VOL_METADATA variable contains the metadata of the volume.

Currently, Ganeti sets this value to originstname+X where X is the instance's name.

The script returns 0 on success.

✨ verify ✨

The verify script checks the consistency of the external parameters (ext-params) β€” see below. The command should take one or more arguments denoting what checks to perform, and return a proper exit code depending on whether the validation failed or succeeded. it's giving quality control. πŸ”

Currently, Ganeti doesn't invoke this script, but it should still be present for future use and for consistency with gnt-os-interface's verify script. manifesting that future. ✨

The script should return 0 on success.

✨ snapshot ✨

The snapshot script takes a snapshot of the given volume. say cheese. πŸ“Έ

The VOL_SNAPSHOT_NAME and VOL_SNAPSHOT_SIZE variables contain the name and size of the snapshot you're about to create.

Currently this operation is used only during gnt-backup export, and Ganeti sets those values to VOL_NAME.snap and VOL_SIZE respectively (see above).

The script returns 0 on success.

Please note: this script is optional, and not all providers should implement it. But of course, if it's not present, instance backup export will not be supported for that provider. so choose wisely. 🫢

✨ open ✨

The open script opens the given volume.

This makes the volume ready for I/O. it's giving pre-game. πŸ”₯

The VOL_OPEN_EXCLUSIVE variable says whether the volume will be opened for exclusive access or not. It's True by default and False (denoting shared access) during migration.

The script returns 0 on success.

Please note: this script is optional and not all providers should implement it.

✨ close ✨

The close script closes the given volume.

This disables I/O on the volume. nap time. 😴

The script returns 0 on success.

Please note: this script is optional and not all providers should implement it.

πŸ“„ TEXT FILES πŸ“„

πŸ“ parameters.list πŸ“

This file declares the parameters your ExtStorage provider supports β€” one parameter per line, with name and description separated by space and/or tab. For example:

fromsnap Snapshot name to create the volume from
nas_ip The IP of the NAS appliance

Then you can use those parameters during instance add like this:

# gnt-instance add --disk=0:fromsnap="file_name",nas_ip="1.2.3.4" ...

✨ EXAMPLES ✨

Okay bestie, real talk β€” these examples all assume you've already got two ExtStorage providers installed and thriving: pvdr1 and pvdr2. That's the whole vibe. Let's go πŸ’…


Adding a new instance with a 10G first disk from pvdr1 and a 20G second disk from pvdr2:

# gnt-instance add -t ext --disk=0:size=10G,provider=pvdr1
                          --disk=1:size=20G,provider=pvdr2

Adding a new instance with a 5G first disk from provider pvdr1, and also passing it the prm1, prm2 parameters with the corresponding values val1, val2:

# gnt-instance add -t ext
                   --disk=0:size=5G,provider=pvdr1,prm1=val1,prm2=val2

Modifying an existing instance of disk type ext by adding a new 30G disk from provider pvdr2:

# gnt-instance modify --disk 1:add,size=30G,provider=pvdr2 <instance>

Modifying an existing instance of disk type ext by adding 2 new disks, from different providers, and passing one parameter for the first one:

# gnt-instance modify --disk 2:add,size=3G,provider=pvdr1,prm1=val1
                      --disk 3:add,size=5G,provider=pvdr2
                      <instance>

πŸ“ NOTES πŸ“

Backwards compatibility

The ExtStorage Interface made its debut in Ganeti 2.7. Ganeti 2.7 and up is compatible with the ExtStorage Interface β€” so if you're on anything β‰₯ 2.7, you're golden 🌟

Common behaviour

All the scripts should display a usage message when they get called with a wrong number of arguments, or when the first argument is -h or --help. Simple as that, no cap.


πŸ› REPORTING BUGS πŸ›

Found a bug? Spill it to the project's issue tracker, or slide into the Ganeti mailing list and talk to the developers directly. They wanna hear from you fr fr 🫢


πŸ‘€ SEE ALSO πŸ‘€

Ganeti overview and specifications:

Ganeti commands:

Ganeti daemons:

Ganeti htools:


Copyright (C) 2006-2015 Google Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

and that's the whole page, bestie!! 🌈 This one's from Ganeti, version 3.1.0~rc2, and it's filed under ganeti-extstorage-interface(7) β€” so now you know exactly where to find it when you inevitably forget everything I just said πŸ˜­πŸ’– go forth and build those disks, you absolute icon πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from