@startuml hide circle hide empty methods hide empty fields namespace juju.charm { class StorageMetadata { Name: string Description : string Kind : StorageKind ReadOnly : bool Shared : bool Location: string CountMin : int CountMax : int } enum StorageKind { block filesystem } Charm "1" *-- "*" StorageMetadata : specifies > } namespace juju.juju.state <> { class Volume { Id : string Life : Life Pool : string Info : VolumeInfo Params : VolumeParams } class VolumeInfo { VolumeId : string Size : int Detachable : bool ExtendedAttrs : map[string]interface{} } class VolumeParams { Size : int } class VolumeAttachment { DeviceName : string } class Filesystem { Id : string Life : Life Pool : string Info : FilesystemInfo Params : FilesystemParams } class FilesystemInfo { FilesystemId : string Size : int Detachable : bool ExtendedAttrs : map[string]interface{} } class FilesystemParams { Size : int Location : string } class FilesystemAttachment { MountPoint : string } class BlockDevice { DeviceName : string HardwareId : string Size : int FilesystemType : string } class StorageConstraints { StorageName : string Size : int Count : int Pool : StoragePool } class StoragePool { Name : string StorageProvider : string Attributes : map[string]string } class StorageInstance { Id : string Pool : StoragePool Life : Life } class StorageAttachment { Location : string } Machine "1" *-- "*" BlockDevice : > has Machine "1" *-- "*" VolumeAttachment : has > Machine "1" *-- "*" FilesystemAttachment : has > Unit "1" *-- "*" StorageInstance : owns (non-shared) > Unit "1" *-- "*" StorageAttachment : has Unit "1" *-- "*" StorageConstraints : records > application "1" *-- "*" StorageInstance : owns (shared) > application "1" *-- "*" StorageConstraints : records > application "1" -- "1" juju.charm.Charm StorageInstance --* StoragePool StorageInstance "1" *-- "*" StorageAttachment : has > Volume "1" *-- "0-1" StorageInstance : assigned > Volume "1" *-- "*" VolumeAttachment Volume "1" *-- "*" VolumeParams Volume "1" *-- "*" VolumeInfo Filesystem "1" *-- "0-1" StorageInstance : assigned to > Filesystem "1" *-- "0-1" FilesystemAttachment : assigned to > Filesystem "1" *-- "0-1" FilesystemParams Filesystem "1" *-- "0-1" FilesystemInfo note as N1 Non-shared storage instances are owned by and managed by a unit, shared storage instances are owned by a service and managed by a unit of that service with with a lease. end note StorageInstance .. N1 note as N2 The machine agent will periodically list block devices on the machine and publish them to state. This gives us a mechanism to determine when a volume is attached and visible to a machine. Additioally, users will later be able to create a Volume from an unused BlockDevice, e.g. hot-plugged disks in MAAS. end note BlockDevice .. N2 note as N3 Volumes and Filesystems will initially be unprovisioned, and will have Params documents associated. Once provisioned, the Params are dropped and replaced with Info. We don't currently, but may later periodically update Info with, e.g. currently available size. end note VolumeInfo .. N3 FilesystemInfo .. N3 VolumeParams .. N3 FilesystemParams .. N3 note as N4 StorageInstance represents a possibly shared store, whereas a StorageAttachment represents the storage instance's attachment to a unit. For non-shared stores, there will be a one-to-one relationship between StorageInstance and StorageAttachment. For shared stores, there may be multiple units attached to a store, potentially with different locations (e.g. block device paths, filesystem mount points). end note StorageInstance .. N4 StorageAttachment .. N4 note as N5 Volumes and Filesystems may be multi-attachable, hence we model attachment as well as the entity itself. Each VolumeAttachment and FilesystemAttachment may have different machine-specific properties (e.g. device name, filesystem mount point). end note Volume .. N5 VolumeAttachment .. N5 Filesystem .. N5 FilesystemAttachment .. N5 note as N6 Volumes and Filesystems may be persistent, and so are not tied to a single storage instance forever. For example, if we deploy a service with persistent storage, and later destroy the unit, we should later be able to reuse that persistent storage with another unit to revive the service. end note Volume .. N6 Filesystem .. N6 StorageInstance .. N6 } namespace juju.names { VolumeTag ..> juju.juju.state.Volume : identifies FilesystemTag ..> juju.juju.state.Filesystem : identifies StorageTag ..> juju.juju.state.StorageInstance : identifies } @enduml