summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@pm.me>2020-12-04 16:24:56 -0500
committerMatthew Heon <mheon@redhat.com>2021-01-14 15:35:33 -0500
commitb53cb57680a6fd7b383636ac2d6cd71003532915 (patch)
tree3979d1f9763326cd4db3a80742cec3a031ca99b2 /pkg
parent2b7793b6121d336a285fb7b9a7612c221cbf63d2 (diff)
downloadpodman-b53cb57680a6fd7b383636ac2d6cd71003532915.tar.gz
podman-b53cb57680a6fd7b383636ac2d6cd71003532915.tar.bz2
podman-b53cb57680a6fd7b383636ac2d6cd71003532915.zip
Initial implementation of volume plugins
This implements support for mounting and unmounting volumes backed by volume plugins. Support for actually retrieving plugins requires a pull request to land in containers.conf and then that to be vendored, and as such is not yet ready. Given this, this code is only compile tested. However, the code for everything past retrieving the plugin has been written - there is support for creating, removing, mounting, and unmounting volumes, which should allow full functionality once the c/common PR is merged. A major change is the signature of the MountPoint function for volumes, which now, by necessity, returns an error. Named volumes managed by a plugin do not have a mountpoint we control; instead, it is managed entirely by the plugin. As such, we need to cache the path in the DB, and calls to retrieve it now need to access the DB (and may fail as such). Notably absent is support for SELinux relabelling and chowning these volumes. Given that we don't manage the mountpoint for these volumes, I am extremely reluctant to try and modify it - we could easily break the plugin trying to chown or relabel it. Also, we had no less than *5* separate implementations of inspecting a volume floating around in pkg/infra/abi and pkg/api/handlers/libpod. And none of them used volume.Inspect(), the only correct way of inspecting volumes. Remove them all and consolidate to using the correct way. Compat API is likely still doing things the wrong way, but that is an issue for another day. Fixes #4304 Signed-off-by: Matthew Heon <matthew.heon@pm.me>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/volumes.go28
-rw-r--r--pkg/api/handlers/libpod/volumes.go51
-rw-r--r--pkg/domain/entities/volumes.go35
-rw-r--r--pkg/domain/infra/abi/containers_stat.go17
-rw-r--r--pkg/domain/infra/abi/system.go12
-rw-r--r--pkg/domain/infra/abi/volumes.go34
6 files changed, 64 insertions, 113 deletions
diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go
index 4903bbad4..82e70eb90 100644
--- a/pkg/api/handlers/compat/volumes.go
+++ b/pkg/api/handlers/compat/volumes.go
@@ -58,10 +58,15 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
}
volumeConfigs := make([]*docker_api_types.Volume, 0, len(vols))
for _, v := range vols {
+ mp, err := v.MountPoint()
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
config := docker_api_types.Volume{
Name: v.Name(),
Driver: v.Driver(),
- Mountpoint: v.MountPoint(),
+ Mountpoint: mp,
CreatedAt: v.CreatedTime().Format(time.RFC3339),
Labels: v.Labels(),
Scope: v.Scope(),
@@ -106,11 +111,16 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
// if using the compat layer and the volume already exists, we
// must return a 201 with the same information as create
if existingVolume != nil && !utils.IsLibpodRequest(r) {
+ mp, err := existingVolume.MountPoint()
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
response := docker_api_types.Volume{
CreatedAt: existingVolume.CreatedTime().Format(time.RFC3339),
Driver: existingVolume.Driver(),
Labels: existingVolume.Labels(),
- Mountpoint: existingVolume.MountPoint(),
+ Mountpoint: mp,
Name: existingVolume.Name(),
Options: existingVolume.Options(),
Scope: existingVolume.Scope(),
@@ -146,10 +156,15 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
+ mp, err := vol.MountPoint()
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
volResponse := docker_api_types.Volume{
Name: config.Name,
Driver: config.Driver,
- Mountpoint: config.MountPoint,
+ Mountpoint: mp,
CreatedAt: config.CreatedTime.Format(time.RFC3339),
Labels: config.Labels,
Options: config.Options,
@@ -173,10 +188,15 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {
utils.VolumeNotFound(w, name, err)
return
}
+ mp, err := vol.MountPoint()
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
volResponse := docker_api_types.Volume{
Name: vol.Name(),
Driver: vol.Driver(),
- Mountpoint: vol.MountPoint(),
+ Mountpoint: mp,
CreatedAt: vol.CreatedTime().Format(time.RFC3339),
Labels: vol.Labels(),
Options: vol.Options(),
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index 6f9537515..38fdf1b4d 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -60,20 +60,13 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- config, err := vol.Config()
+ inspectOut, err := vol.Inspect()
if err != nil {
utils.InternalServerError(w, err)
return
}
volResponse := entities.VolumeConfigResponse{
- Name: config.Name,
- Driver: config.Driver,
- Mountpoint: config.MountPoint,
- CreatedAt: config.CreatedTime,
- Labels: config.Labels,
- Options: config.Options,
- UID: config.UID,
- GID: config.GID,
+ InspectVolumeData: *inspectOut,
}
utils.WriteResponse(w, http.StatusCreated, volResponse)
}
@@ -88,27 +81,13 @@ func InspectVolume(w http.ResponseWriter, r *http.Request) {
utils.VolumeNotFound(w, name, err)
return
}
- var uid, gid int
- uid, err = vol.UID()
+ inspectOut, err := vol.Inspect()
if err != nil {
- utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err)
- return
- }
- gid, err = vol.GID()
- if err != nil {
- utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err)
+ utils.InternalServerError(w, err)
return
}
volResponse := entities.VolumeConfigResponse{
- Name: vol.Name(),
- Driver: vol.Driver(),
- Mountpoint: vol.MountPoint(),
- CreatedAt: vol.CreatedTime(),
- Labels: vol.Labels(),
- Scope: vol.Scope(),
- Options: vol.Options(),
- UID: uid,
- GID: gid,
+ InspectVolumeData: *inspectOut,
}
utils.WriteResponse(w, http.StatusOK, volResponse)
}
@@ -143,27 +122,13 @@ func ListVolumes(w http.ResponseWriter, r *http.Request) {
}
volumeConfigs := make([]*entities.VolumeListReport, 0, len(vols))
for _, v := range vols {
- var uid, gid int
- uid, err = v.UID()
+ inspectOut, err := v.Inspect()
if err != nil {
- utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err)
- return
- }
- gid, err = v.GID()
- if err != nil {
- utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err)
+ utils.InternalServerError(w, err)
return
}
config := entities.VolumeConfigResponse{
- Name: v.Name(),
- Driver: v.Driver(),
- Mountpoint: v.MountPoint(),
- CreatedAt: v.CreatedTime(),
- Labels: v.Labels(),
- Scope: v.Scope(),
- Options: v.Options(),
- UID: uid,
- GID: gid,
+ InspectVolumeData: *inspectOut,
}
volumeConfigs = append(volumeConfigs, &entities.VolumeListReport{VolumeConfigResponse: config})
}
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index 06438f5e9..c826ee389 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -2,8 +2,8 @@ package entities
import (
"net/url"
- "time"
+ "github.com/containers/podman/v2/libpod/define"
docker_api_types "github.com/docker/docker/api/types"
docker_api_types_volume "github.com/docker/docker/api/types/volume"
)
@@ -26,38 +26,7 @@ type IDOrNameResponse struct {
}
type VolumeConfigResponse struct {
- // Name is the name of the volume.
- Name string `json:"Name"`
- // Driver is the driver used to create the volume.
- // This will be properly implemented in a future version.
- Driver string `json:"Driver"`
- // Mountpoint is the path on the host where the volume is mounted.
- Mountpoint string `json:"Mountpoint"`
- // CreatedAt is the date and time the volume was created at. This is not
- // stored for older Libpod volumes; if so, it will be omitted.
- CreatedAt time.Time `json:"CreatedAt,omitempty"`
- // Status is presently unused and provided only for Docker compatibility.
- // In the future it will be used to return information on the volume's
- // current state.
- Status map[string]string `json:"Status,omitempty"`
- // Labels includes the volume's configured labels, key:value pairs that
- // can be passed during volume creation to provide information for third
- // party tools.
- Labels map[string]string `json:"Labels"`
- // Scope is unused and provided solely for Docker compatibility. It is
- // unconditionally set to "local".
- Scope string `json:"Scope"`
- // Options is a set of options that were used when creating the volume.
- // It is presently not used.
- Options map[string]string `json:"Options"`
- // UID is the UID that the volume was created with.
- UID int `json:"UID"`
- // GID is the GID that the volume was created with.
- GID int `json:"GID"`
- // Anonymous indicates that the volume was created as an anonymous
- // volume for a specific container, and will be be removed when any
- // container using it is removed.
- Anonymous bool `json:"Anonymous"`
+ define.InspectVolumeData
}
// VolumeInfo Volume list response
diff --git a/pkg/domain/infra/abi/containers_stat.go b/pkg/domain/infra/abi/containers_stat.go
index 5b43ee2f4..931e77026 100644
--- a/pkg/domain/infra/abi/containers_stat.go
+++ b/pkg/domain/infra/abi/containers_stat.go
@@ -144,16 +144,29 @@ func resolveContainerPaths(container *libpod.Container, mountPoint string, conta
}
if volume != nil {
logrus.Debugf("Container path %q resolved to volume %q on path %q", containerPath, volume.Name(), searchPath)
+
+ // TODO: We really need to force the volume to mount
+ // before doing this, but that API is not exposed
+ // externally right now and doing so is beyond the scope
+ // of this commit.
+ mountPoint, err := volume.MountPoint()
+ if err != nil {
+ return "", "", err
+ }
+ if mountPoint == "" {
+ return "", "", errors.Errorf("volume %s is not mounted, cannot copy into it", volume.Name())
+ }
+
// We found a matching volume for searchPath. We now
// need to first find the relative path of our input
// path to the searchPath, and then join it with the
// volume's mount point.
pathRelativeToVolume := strings.TrimPrefix(pathRelativeToContainerMountPoint, searchPath)
- absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(volume.MountPoint(), pathRelativeToVolume)
+ absolutePathOnTheVolumeMount, err := securejoin.SecureJoin(mountPoint, pathRelativeToVolume)
if err != nil {
return "", "", err
}
- return volume.MountPoint(), absolutePathOnTheVolumeMount, nil
+ return mountPoint, absolutePathOnTheVolumeMount, nil
}
if mount := findBindMount(container, searchPath); mount != nil {
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 97fa9d374..f29b98696 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -312,7 +312,17 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
var reclaimableSize int64
for _, v := range vols {
var consInUse int
- volSize, err := sizeOfPath(v.MountPoint())
+ mountPoint, err := v.MountPoint()
+ if err != nil {
+ return nil, err
+ }
+ if mountPoint == "" {
+ // We can't get any info on this volume, as it's not
+ // mounted.
+ // TODO: fix this.
+ continue
+ }
+ volSize, err := sizeOfPath(mountPoint)
if err != nil {
return nil, err
}
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
index 3c9dd9fc0..823605052 100644
--- a/pkg/domain/infra/abi/volumes.go
+++ b/pkg/domain/infra/abi/volumes.go
@@ -103,25 +103,12 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin
}
reports := make([]*entities.VolumeInspectReport, 0, len(vols))
for _, v := range vols {
- var uid, gid int
- uid, err = v.UID()
- if err != nil {
- return nil, nil, err
- }
- gid, err = v.GID()
+ inspectOut, err := v.Inspect()
if err != nil {
return nil, nil, err
}
config := entities.VolumeConfigResponse{
- Name: v.Name(),
- Driver: v.Driver(),
- Mountpoint: v.MountPoint(),
- CreatedAt: v.CreatedTime(),
- Labels: v.Labels(),
- Scope: v.Scope(),
- Options: v.Options(),
- UID: uid,
- GID: gid,
+ InspectVolumeData: *inspectOut,
}
reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: &config})
}
@@ -155,25 +142,12 @@ func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeL
}
reports := make([]*entities.VolumeListReport, 0, len(vols))
for _, v := range vols {
- var uid, gid int
- uid, err = v.UID()
- if err != nil {
- return nil, err
- }
- gid, err = v.GID()
+ inspectOut, err := v.Inspect()
if err != nil {
return nil, err
}
config := entities.VolumeConfigResponse{
- Name: v.Name(),
- Driver: v.Driver(),
- Mountpoint: v.MountPoint(),
- CreatedAt: v.CreatedTime(),
- Labels: v.Labels(),
- Scope: v.Scope(),
- Options: v.Options(),
- UID: uid,
- GID: gid,
+ InspectVolumeData: *inspectOut,
}
reports = append(reports, &entities.VolumeListReport{VolumeConfigResponse: config})
}