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