1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
|
//go:build !remote
package libpod
import (
"time"
"github.com/containers/podman/v5/libpod/define"
"github.com/containers/podman/v5/libpod/lock"
"github.com/containers/podman/v5/libpod/plugin"
"github.com/containers/storage/pkg/directory"
)
// Volume is a libpod named volume.
// Named volumes may be shared by multiple containers, and may be created using
// more complex options than normal bind mounts. They may be backed by a mounted
// filesystem on the host.
type Volume struct {
config *VolumeConfig
state *VolumeState
ignoreIfExists bool
valid bool
plugin *plugin.VolumePlugin
runtime *Runtime
lock lock.Locker
}
// VolumeConfig holds the volume's immutable configuration.
type VolumeConfig struct {
// Name of the volume.
Name string `json:"name"`
// ID of the volume's lock.
LockID uint32 `json:"lockID"`
// Labels for the volume.
Labels map[string]string `json:"labels"`
// The volume driver. Empty string or local does not activate a volume
// driver, all other values will.
Driver string `json:"volumeDriver"`
// The location the volume is mounted at.
MountPoint string `json:"mountPoint"`
// Time the volume was created.
CreatedTime time.Time `json:"createdAt,omitempty"`
// Options to pass to the volume driver. For the local driver, this is
// a list of mount options. For other drivers, they are passed to the
// volume driver handling the volume.
Options map[string]string `json:"volumeOptions,omitempty"`
// Whether this volume is anonymous (will be removed on container exit)
IsAnon bool `json:"isAnon"`
// UID the volume will be created as.
UID int `json:"uid"`
// GID the volume will be created as.
GID int `json:"gid"`
// Size maximum of the volume.
Size uint64 `json:"size"`
// Inodes maximum of the volume.
Inodes uint64 `json:"inodes"`
// DisableQuota indicates that the volume should completely disable using any
// quota tracking.
DisableQuota bool `json:"disableQuota,omitempty"`
// Timeout allows users to override the default driver timeout of 5 seconds
Timeout *uint `json:"timeout,omitempty"`
// StorageName is the name of the volume in c/storage. Only used for
// image volumes.
StorageName string `json:"storageName,omitempty"`
// StorageID is the ID of the volume in c/storage. Only used for image
// volumes.
StorageID string `json:"storageID,omitempty"`
// StorageImageID is the ID of the image the volume was based off of.
// Only used for image volumes.
StorageImageID string `json:"storageImageID,omitempty"`
// MountLabel is the SELinux label to assign to mount points
MountLabel string `json:"mountlabel,omitempty"`
}
// VolumeState holds the volume's mutable state.
// Volumes are not guaranteed to have a state. Only volumes using the Local
// driver that have mount options set will create a state.
type VolumeState struct {
// Mountpoint is the location where the volume was mounted.
// This is only used for volumes using a volume plugin, which will mount
// at non-standard locations.
MountPoint string `json:"mountPoint,omitempty"`
// MountCount is the number of times this volume has been requested to
// be mounted.
// It is incremented on mount() and decremented on unmount().
// On incrementing from 0, the volume will be mounted on the host.
// On decrementing to 0, the volume will be unmounted on the host.
MountCount uint `json:"mountCount"`
// NeedsCopyUp indicates that the next time the volume is mounted into
// a container, the container will "copy up" the contents of the
// mountpoint into the volume.
// This should only be done once. As such, this is set at container
// create time, then cleared after the copy up is done and never set
// again.
NeedsCopyUp bool `json:"notYetMounted,omitempty"`
// NeedsChown indicates that the next time the volume is mounted into
// a container, the container will chown the volume to the container process
// UID/GID.
NeedsChown bool `json:"notYetChowned,omitempty"`
// Indicates that a copy-up event occurred during the current mount of
// the volume into a container.
// We use this to determine if a chown is appropriate.
CopiedUp bool `json:"copiedUp,omitempty"`
// UIDChowned is the UID the volume was chowned to.
UIDChowned int `json:"uidChowned,omitempty"`
// GIDChowned is the GID the volume was chowned to.
GIDChowned int `json:"gidChowned,omitempty"`
}
// Name retrieves the volume's name
func (v *Volume) Name() string {
return v.config.Name
}
// Returns the size on disk of volume
func (v *Volume) Size() (uint64, error) {
size, err := directory.Size(v.config.MountPoint)
return uint64(size), err
}
// Driver retrieves the volume's driver.
func (v *Volume) Driver() string {
return v.config.Driver
}
// Scope retrieves the volume's scope.
// Libpod does not implement volume scoping, and this is provided solely for
// Docker compatibility. It returns only "local".
func (v *Volume) Scope() string {
return "local"
}
// Labels returns the volume's labels
func (v *Volume) Labels() map[string]string {
labels := make(map[string]string)
for key, value := range v.config.Labels {
labels[key] = value
}
return labels
}
// MountPoint returns the volume's mountpoint on the host
func (v *Volume) MountPoint() (string, error) {
// For the sake of performance, avoid locking unless we have to.
if v.UsesVolumeDriver() || v.config.Driver == define.VolumeDriverImage {
v.lock.Lock()
defer v.lock.Unlock()
if err := v.update(); err != nil {
return "", err
}
}
return v.mountPoint(), nil
}
// MountCount returns the volume's mountcount on the host from state
// Useful in determining if volume is using plugin or a filesystem mount and its mount
func (v *Volume) MountCount() (uint, error) {
v.lock.Lock()
defer v.lock.Unlock()
if err := v.update(); err != nil {
return 0, err
}
return v.state.MountCount, nil
}
// Internal-only helper for volume mountpoint
func (v *Volume) mountPoint() string {
if v.UsesVolumeDriver() || v.config.Driver == define.VolumeDriverImage {
return v.state.MountPoint
}
return v.config.MountPoint
}
// Options return the volume's options
func (v *Volume) Options() map[string]string {
options := make(map[string]string)
for k, v := range v.config.Options {
options[k] = v
}
return options
}
// Anonymous returns whether this volume is anonymous. Anonymous volumes were
// created with a container, and will be removed when that container is removed.
func (v *Volume) Anonymous() bool {
return v.config.IsAnon
}
// UID returns the UID the volume will be created as.
func (v *Volume) UID() (int, error) {
v.lock.Lock()
defer v.lock.Unlock()
if err := v.update(); err != nil {
return -1, err
}
return v.uid(), nil
}
// Internal, unlocked accessor for UID.
func (v *Volume) uid() int {
if v.state.UIDChowned > 0 {
return v.state.UIDChowned
}
return v.config.UID
}
// GID returns the GID the volume will be created as.
func (v *Volume) GID() (int, error) {
v.lock.Lock()
defer v.lock.Unlock()
if err := v.update(); err != nil {
return -1, err
}
return v.gid(), nil
}
// Internal, unlocked accessor for GID.
func (v *Volume) gid() int {
if v.state.GIDChowned > 0 {
return v.state.GIDChowned
}
return v.config.GID
}
// CreatedTime returns the time the volume was created at. It was not tracked
// for some time, so older volumes may not contain one.
func (v *Volume) CreatedTime() time.Time {
return v.config.CreatedTime
}
// Config returns the volume's configuration.
func (v *Volume) Config() (*VolumeConfig, error) {
config := VolumeConfig{}
err := JSONDeepCopy(v.config, &config)
return &config, err
}
// VolumeInUse goes through the container dependencies of a volume
// and checks if the volume is being used by any container.
func (v *Volume) VolumeInUse() ([]string, error) {
v.lock.Lock()
defer v.lock.Unlock()
if !v.valid {
return nil, define.ErrVolumeRemoved
}
return v.runtime.state.VolumeInUse(v)
}
// IsDangling returns whether this volume is dangling (unused by any
// containers).
func (v *Volume) IsDangling() (bool, error) {
ctrs, err := v.VolumeInUse()
if err != nil {
return false, err
}
return len(ctrs) == 0, nil
}
// UsesVolumeDriver determines whether the volume uses a volume driver. Volume
// drivers are pluggable backends for volumes that will manage the storage and
// mounting.
func (v *Volume) UsesVolumeDriver() bool {
if v.config.Driver == define.VolumeDriverImage {
if _, ok := v.runtime.config.Engine.VolumePlugins[v.config.Driver]; ok {
return true
}
return false
}
return !(v.config.Driver == define.VolumeDriverLocal || v.config.Driver == "")
}
func (v *Volume) Mount() (string, error) {
v.lock.Lock()
defer v.lock.Unlock()
err := v.mount()
return v.config.MountPoint, err
}
func (v *Volume) Unmount() error {
v.lock.Lock()
defer v.lock.Unlock()
return v.unmount(false)
}
func (v *Volume) NeedsMount() bool {
return v.needsMount()
}
|