@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 <<Database>> {
	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 >

	Service "1" *-- "*" StorageInstance : owns (shared) >
	Service "1" *-- "*" StorageConstraints : records >
	Service "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
