Implementing storage

The storage feature can be implemented in any charm running on Juju version 1.25 or later. For applications that can take advantage of block storage or other types of storage there are two additional storage hooks for the code to react to storage changes.

If you are looking for information on the various storage provider types or how to deploy charms that use storage features see Using Juju storage.

Adding storage

Storage requirements may be added to the metadata.yaml file of the charm as follows:

storage:
  data:
    type: filesystem
    description: junk storage
    shared: false # not yet supported, see description below
    read-only: false # not yet supported, see description below
    minimum-size: 100M
    location: /srv/data

In this definition, the charm is asking for storage called 'data', and it further defines a type and location. It is possible to specify as many entries as desired for storage, and all but the 'type' key are optional. The 'type' attribute specifies the type of the storage: filesystem or block (i.e. block device/disk). The 'minimum-size' attribute specifies the minimum size of the store, overriding the default of 1GiB if the user does not specify a size. The location specifies the path at which to mount filesystem-type storage. The 'read-only' and 'shared' attributes are currently not handled. Support will be added in a future version of Juju.

A filesystem-type store yields a directory in which the charm may store files. Block-type stores yield raw block devices -- typically disks or logical volumes. If the charm specifies a filesystem-type store, and the storage provider supports provisioning only disks, then a disk will be created, attached, partitioned, and a filesystem created on top. The filesystem will be presented to the charm, and rest of the details will be managed by Juju.

By default, stores are singletons; a charm will have exactly one of the specified store. It is also possible for a charm to specify storage that may have multiple instantiations, e.g. multiple disks to add to a pool. To do this, you can specify the "multiple" attribute:

storage:
  disks:
    type: block
    multiple:
      range: 0-10

The definition above indicates that the charm may have anywhere from zero to ten block devices allocated to the 'disks' store. The formats supported by "range" are: m (a fixed number), m-n (an explicit range), and m- (a minimum number).

Unless a number is explicitly specified during deployment, units of the application will be allocated the minimum number of storage instances specified in the charm metadata. It is then possible to add instances (up to the maximum) by using the juju storage add command, or using the storage-add hook tool.

Storage hooks

For each storage entity defined in the metadata.yaml file, the following hooks may be implemented:

Each hook is prefixed with the name of the store, similar to how relation hooks are prefixed with the name of the relation. So, for example, if we had specified a need for storage labeled 'data', we would probably want to implement the hook 'data-storage-attached', which might look something like:

#!/bin/bash
set -eux
mountpoint=$(storage-get -s osd-devices/1 location)
sed -i /etc/myservice.conf "s,MOUNTPOINT,$mountpoint"
status-set maintenance “Storage ready and mounted.”

The [name]-storage-attached hooks will be run before the install hook, so that the installation routine may use the storage. The [name]-storage-detaching hook will be run before storage is detached, and always before the stop hook is run, to allow the charm to gracefully release resources before they are removed and before the unit terminates.

There are several hook tools available for dealing with storage within a charm, described below

  • storage-list

    storage-list may be used to list storage instances that are attached to the unit. The names returned may be passed through to storage-get.

  • storage-get

    storage-get may be used to obtain information about storage being attached to, or detaching from, the unit. If the executing hook is a storage hook, information about the storage related to the hook will be reported; this may be overridden by specifying the name of the storage as reported by storage-list, and must be specified for non-storage hooks.

    storage-get should be used to identify the storage location during storage-attached and storage-detaching hooks. The exception to this is when the charm specifies a static location for singleton stores.

  • storage-add

    storage-add may be used to add storage to the unit. The tool takes the name of the storage (as in the charm metadata), and optionally the number of storage instances to add; by default it will add a single instance.

Persistent storage

Some providers have the option to attach and detach storage from the application that is consuming it. This means that even after applications have been removed, the storage and its contents may still exist in your cloud. This can be useful for backup, recovery, or transport purposes. Storage is now destroyed only when the model is destroyed or when the storage is manually removed.

Future work

Shared storage

Some providers, typically network filesystems, permit attaching storage to multiple machines. We intend to support multiple attachment within Juju. Shared storage will be assigned to a application, and each unit of the application will attach to the same shared storage instance.